home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 7: Sunsite
/
Linux Cubed Series 7 - Sunsite Vol 1.iso
/
system
/
network
/
samba
/
patches
/
samba-1.000
/
samba-1
Wrap
Text File
|
1996-07-18
|
418KB
|
13,301 lines
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/README samba-1.9.16alpha11/README
--- samba-1.9.16alpha10/README Tue May 28 23:37:21 1996
+++ samba-1.9.16alpha11/README Sun Jun 30 15:17:17 1996
@@ -10,21 +10,27 @@
WHAT CAN SAMBA DO?
==================
-Here is a very short list of what samba includes, and what it does
+Here is a very short list of what samba includes, and what it does.
-- a SMB server, to provide LanManager style file and print services to PCs
+- a SMB server, to provide Windows NT and LAN Manager-style file and print
+ services to SMB clients such as Windows 95, Warp Server, smbfs and others.
-- a Netbios (rfc1001/1002) nameserver
+- a Netbios (rfc1001/1002) nameserver, which among other things gives
+ browsing support. Samba can be the master browser on your LAN if you wish.
- a ftp-like SMB client so you can access PC resources (disks and
-printers) from unix
+printers) from unix, Netware and other operating systems
- a tar extension to the client for backing up PCs
+For a much better overview have a look at the web site at
+http://samba.canberra.edu.au/pub/samba, and browse the user survey.
+
Related packages include:
-- ksmbfs, a linux-only filesystem allowing you to mount remote SMB
-filesystems from PCs on your linux box
+- smbfs, a linux-only filesystem allowing you to mount remote SMB
+filesystems from PCs on your linux box. This is included as standard with
+Linux 2.0 and later.
- tcpdump-smb, a extension to tcpdump to allow you to investigate SMB
networking problems over netbeui and tcp/ip
@@ -47,7 +53,8 @@
Remember that free software of this kind lives or dies by the response
we get. If noone tells us they like it then we'll probably move onto
-something else.
+something else. However, as you can see from the user survey quite a lot of
+people do seem to like it at the moment :-)
Andrew Tridgell
Email: samba-bugs@samba.anu.edu.au
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/docs/announce samba-1.9.16alpha11/docs/announce
--- samba-1.9.16alpha10/docs/announce Tue May 28 23:37:23 1996
+++ samba-1.9.16alpha11/docs/announce Sun Jun 30 15:17:19 1996
@@ -4,19 +4,21 @@
What is Samba?
--------------
-Samba is a Unix based SMB file server. This allows a Unix host to
-act as a file and print server for SMB clients. This includes
+Samba is a SMB file server that runs on Unix and other operating systems.
+It allows these operating systems (currently Unix, Netware, OS/2 and
+AmigaDOS) to act as a file and print server for SMB clients. There are many
Lan-Manager compatible clients such as LanManager for DOS, Windows for
Workgroups, Windows NT, Windows 95, OS/2, Pathworks and many more.
-The package also includes a Unix SMB client and a netbios nameserver.
+The package also includes a SMB client for accessing other SMB servers
+and a netbios nameserver for browsing support.
What can it do for me?
----------------------
If you have any PCs running SMB clients, such as a PC running Windows
-for Workgroups, then you can mount file space or printers from a unix
-host, so that directories, files and printers on the unix host are
+for Workgroups, then you can mount file space or printers on a Samba
+host, so that directories, files and printers on the host are
available on the PC.
The client part of the package will also allow you to attach to other
@@ -31,7 +33,7 @@
Samba supports many features that are not supported in other SMB
implementations (all of which are commercial). Some of it's features
-include host as well as username/password security, a unix client,
+include host as well as username/password security, a client,
automatic home directory exporting, automatic printer exporting, dead
connection timeouts, umask support, guest connections, name mangling
and hidden and system attribute mapping. Look at the man pages
@@ -66,7 +68,7 @@
GNU Public licence in source code form at no cost. Please read the
file COPYING that comes with the package for more information.
-What flavours of unix does it support?
+What operating systems does it support?
---------------------------------------
The code has been written to be as portable as possible. It has been
@@ -79,7 +81,9 @@
Domain/OS and DGUX.
Some of these have received more testing than others. If it doesn't
-work with your unix then it should be easy to fix.
+work with your unix then it should be easy to fix. It has also been ported
+to Netware, OS/2 and the Amiga. A VMS port is underway. See the web site
+for more details.
Who wrote it?
-------------
@@ -125,5 +129,5 @@
A WWW site with lots of Samba info can be found at
http://samba.canberra.edu.au/pub/samba/
-Andrew Tridgell (Contact: samba-bugs@anu.edu.au)
-January 1995
+The Samba Team (Contact: samba-bugs@anu.edu.au)
+June 1996
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/docs/security_level.txt samba-1.9.16alpha11/docs/security_level.txt
--- samba-1.9.16alpha10/docs/security_level.txt Thu May 30 10:05:51 1996
+++ samba-1.9.16alpha11/docs/security_level.txt Sun Jun 30 15:17:19 1996
@@ -42,14 +42,14 @@
operation. The client is expecting a password to be associated with
each share, independent of the user. This means that samba has to work
out what username the client probably wants to use. It is never
-explicitly sent the username. A "real" SMB server like NT actually
-associates passwords directly with shares in share level security, but
+explicitly sent the username. Some commercial SMB servers such as NT actually
+associate passwords directly with shares in share level security, but
samba always uses the unix authentication scheme where it is a
username/password that is authenticated, not a "share/password".
Many clients send a "session setup" even if the server is in share
level security. They normally send a valid username but no
-password. Samba records this username is a list of "possible
+password. Samba records this username in a list of "possible
usernames". When the client then does a "tree connection" it also adds
to this list the name of the share they try to connect to (useful for
home directories) and any users listed in the "user =" smb.conf
@@ -75,4 +75,5 @@
enabled to support this feature, and you have to maintain a separate
smbpasswd file with SMB style encrypted passwords. It is
cryptographically impossible to translate from unix style encryption
-to SMB style encryption.
+to SMB style encryption, although there are some fairly simple management
+schemes by which the two could be kept in sync.
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/examples/simple/smb.conf samba-1.9.16alpha11/examples/simple/smb.conf
--- samba-1.9.16alpha10/examples/simple/smb.conf Sat May 4 17:50:25 1996
+++ samba-1.9.16alpha11/examples/simple/smb.conf Mon Jul 15 17:54:57 1996
@@ -80,11 +80,13 @@
writable = no
create mode = 0700
-; you might also want this one
+; you might also want this one, notice that it is read only so as not to give
+; people without an account write access.
+;
; [tmp]
; comment = Temporary file space
; path = /tmp
-; read only = no
+; read only = yes
; public = yes
;
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/Makefile samba-1.9.16alpha11/source/Makefile
--- samba-1.9.16alpha10/source/Makefile Mon Jun 10 15:18:47 1996
+++ samba-1.9.16alpha11/source/Makefile Thu Jul 18 20:53:13 1996
@@ -1,6 +1,6 @@
###########################################################################
# Makefile for Samba SMB client/server for unix
-# Copyright Andrew Tridgell 1992,1993,1994
+# Copyright Andrew Tridgell 1992-1996
###########################################################################
# The base manpages directory to put the man pages in
@@ -101,6 +101,15 @@
#VTP_OBJ = vt_mode.o
######################################
+######################################
+# WHICH AWK? awk is used for automatic prototype generation. GNU awk works
+# where inferior awks don't. Sun is one manufacturer who supplies both
+# a broken awk called 'awk' and a fixed one called 'nawk'. mkproto.awk will
+# only work with the latter, and even that isn't as good as free GNU awk.
+#
+# Leave this uncommented; the OS-specific stuff will override it if required
+AWK = awk
+######################################
#####################################
# WHICH OPERATING SYSTEM?
@@ -148,7 +157,7 @@
# contributed by Andrew.Tridgell@anu.edu.au
# FLAGSM = -DSUNOS4
# LIBSM =
-
+# AWK = nawk
# Use this for Linux with shadow passwords
# contributed by Andrew.Tridgell@anu.edu.au
@@ -177,6 +186,7 @@
# contributed by Andrew.Tridgell@anu.edu.au
# FLAGSM = -DSUNOS5 -DSHADOW_PWD -DNETGROUP
# LIBSM = -lsocket -lnsl
+# AWK = nawk
# This is for SVR4
@@ -491,8 +501,8 @@
@echo "Using CFLAGS = $(CFLAGS)"
@echo "Using LIBS = $(LIBS)"
-INCLUDES1 = version.h local.h includes.h smb.h loadparm.h params.h smbpass.h
-INCLUDES2 = pcap.h trans2.h reply.h
+INCLUDES1 = version.h local.h includes.h smb.h smbpass.h
+INCLUDES2 = trans2.h reply.h
INCLUDES = $(INCLUDES1) $(INCLUDES2)
UTILOBJ1 = util.o system.o charset.o kanji.o fault.o smbencrypt.o charcnv.o
@@ -502,8 +512,10 @@
SMBDOBJ1 = $(PARAMOBJ) trans2.o message.o dir.o printing.o locking.o
SMBDOBJ2 = ipc.o reply.o mangle.o chgpasswd.o password.o quotas.o uid.o
SMBDOBJ = predict.o $(SMBDOBJ1) $(SMBDOBJ2) $(VTP_OBJ)
-NMBDOBJ1 = $(UTILOBJ) nmblib.o nameresp.o nmbsync.o nameannounce.o namedb.o nameelect.o
-NMBDOBJ = $(NMBDOBJ1) namework.o nameserv.o clientutil.o
+NMBDOBJ1 = nmblib.o namepacket.o nameresp.o nmbsync.o nameannounce.o nameelect.o
+NMBDOBJ2 = namedbresp.o namedbwork.o namedbserver.o namedbsubnet.o namedbname.o
+NMBDOBJ3 = nameservresp.o nameservreply.o namelogon.o namebrowse.o namework.o nameserv.o clientutil.o
+NMBDOBJ = $(UTILOBJ) $(NMBDOBJ1) $(NMBDOBJ2) $(NMBDOBJ3)
.SUFFIXES:
.SUFFIXES: .c .o .h
@@ -553,7 +565,7 @@
@$(SHELL) $(srcdir)installbin.sh $(INSTALLPERMS) $(BASEDIR) $(BINDIR) $(LIBDIR) $(VARDIR) $(PROGS)
installscripts:
- @$(SHELL) $(srcdir)installscripts.sh $(INSTALLPERMS) $(BINDIR) $(srcdir)
+ @$(SHELL) $(srcdir)installscripts.sh $(INSTALLPERMS) $(BINDIR) $(SCRIPTS)
# revert to the previously installed version
revert:
@@ -562,11 +574,23 @@
installman:
@$(SHELL) $(srcdir)installman.sh $(MANDIR) $(srcdir)
+uninstall: uninstallman uninstallbin uninstallscripts
+
+uninstallman:
+ @$(SHELL) $(srcdir)uninstallman.sh $(MANDIR) $(srcdir)
+
+uninstallbin:
+ @$(SHELL) $(srcdir)uninstallbin.sh $(INSTALLPERMS) $(BASEDIR) $(BINDIR) $(LIBDIR) $(VARDIR) $(PROGS)
+
+uninstallscripts:
+ @$(SHELL) $(srcdir)uninstallscripts.sh $(INSTALLPERMS) $(BINDIR) $(SCRIPTS)
+
clean:
rm -f core *.o *~ $(PROGS)
proto:
- cat *.c | awk -f mkproto.awk > proto.h
+ @$(SHELL) $(srcdir)checkos.sh $(FLAGSM)
+ $(AWK) -f mkproto.awk *.c > proto.h
realclean: clean
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/access.c samba-1.9.16alpha11/source/access.c
--- samba-1.9.16alpha10/source/access.c Mon Jun 10 15:18:48 1996
+++ samba-1.9.16alpha11/source/access.c Mon Jul 15 17:55:03 1996
@@ -5,7 +5,7 @@
The code is used here with permission.
The code has been considerably changed from the original. Bug reports
-should be sent to Andrew.Tridgell@anu.edu.au
+should be sent to samba-bugs@samba.anu.edu.au
*/
#include "includes.h"
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/change-log samba-1.9.16alpha11/source/change-log
--- samba-1.9.16alpha10/source/change-log Wed May 29 14:28:46 1996
+++ samba-1.9.16alpha11/source/change-log Mon Jul 15 17:55:03 1996
@@ -1,10 +1,13 @@
-Change Log for Samba
+SUPERCEDED Change Log for Samba
+^^^^^^^^^^
Unless otherwise attributed, all changes were made by
-Andrew.Tridgell@anu.edu.au
+Andrew.Tridgell@anu.edu.au. All bugs to samba-bugs@samba.anu.edu.au.
NOTE: THIS LOG IS IN CHRONOLOGICAL ORDER
+NOTE: From now on the cvs.log file will be used to give a complete log of
+changes to samba. This change-log is now obsolete.
1.5.00 announced to mailing list
@@ -1872,4 +1875,4 @@
Tony Aiuto (tony@ics.com)
make max disk size local
-
\ No newline at end of file
+
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/checkos.sh samba-1.9.16alpha11/source/checkos.sh
--- samba-1.9.16alpha10/source/checkos.sh Sat May 4 17:50:25 1996
+++ samba-1.9.16alpha11/source/checkos.sh Mon Jul 15 17:55:03 1996
@@ -5,11 +5,11 @@
You forgot to uncomment a host type and flags in the Makefile. If your
host type does not appear in the Makefile then choose one that you
think is similar and once you have it working then add a new host type
-to the Makefile and includes.h. Please also send me the output of the
+to the Makefile and includes.h. Please also send us the output of the
command "uname" on your system so this can be automated at some future
time.
-Andrew.Tridgell@anu.edu.au
+samba-bugs@samba.anu.edu.au
=====================================================================
EOF
exit 1
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/client.c samba-1.9.16alpha11/source/client.c
--- samba-1.9.16alpha10/source/client.c Mon Jun 10 15:18:49 1996
+++ samba-1.9.16alpha11/source/client.c Thu Jul 18 20:53:15 1996
@@ -2874,6 +2874,21 @@
return(True);
}
+static struct {
+ int prot;
+ char *name;
+} prots[] = {
+ {PROTOCOL_CORE,"PC NETWORK PROGRAM 1.0"},
+ {PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"},
+ {PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"},
+ {PROTOCOL_LANMAN1,"LANMAN1.0"},
+ {PROTOCOL_LANMAN2,"LM1.2X002"},
+ {PROTOCOL_LANMAN2,"Samba"},
+ {PROTOCOL_NT1,"NT LM 0.12"},
+ {PROTOCOL_NT1,"NT LANMAN 1.0"},
+ {-1,NULL}
+};
+
/****************************************************************************
send a login command
@@ -2887,22 +2902,6 @@
int sec_mode=0;
int crypt_len;
int max_vcs=0;
- struct {
- int prot;
- char *name;
- }
- prots[] =
- {
- {PROTOCOL_CORE,"PC NETWORK PROGRAM 1.0"},
- {PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"},
- {PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"},
- {PROTOCOL_LANMAN1,"LANMAN1.0"},
- {PROTOCOL_LANMAN2,"LM1.2X002"},
- {PROTOCOL_LANMAN2,"Samba"},
- {PROTOCOL_NT1,"NT LM 0.12"},
- {PROTOCOL_NT1,"NT LANMAN 1.0"},
- {-1,NULL}
- };
char *pass = NULL;
pstring dev;
char *p;
@@ -3586,7 +3585,7 @@
/****************************************************************************
try and browse available connections on a host
****************************************************************************/
-static BOOL list_servers()
+static BOOL list_servers(char *wk_grp)
{
char *rparam = NULL;
char *rdata = NULL;
@@ -3601,7 +3600,7 @@
p = param;
SSVAL(p,0,0x68); /* api number */
p += 2;
- strcpy(p,"WrLehDO");
+ strcpy(p,"WrLehDz");
p = skip_string(p,1);
strcpy(p,"B16BBDz");
@@ -3616,6 +3615,11 @@
SIVAL(p,0,SV_TYPE_ALL);
+ p += 4;
+
+ strcpy(p, wk_grp);
+ p = skip_string(p,1);
+
if (call_api(PTR_DIFF(p+4,param),0,
8,10000,
&rprcnt,&rdrcnt,
@@ -3652,7 +3656,7 @@
if (rparam) {free(rparam); rparam = NULL;}
if (rdata) {free(rdata); rdata = NULL;}
- SIVAL(p,0,SV_TYPE_DOMAIN_ENUM);
+ SIVAL(p,0,0x7fffffff);
if (call_api(PTR_DIFF(p+4,param),0,
8,10000,
@@ -4392,9 +4396,9 @@
sleep(1);
browse_host(True);
}
- if (!list_servers()) {
+ if (!list_servers(workgroup)) {
sleep(1);
- list_servers();
+ list_servers(workgroup);
}
send_logout();
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/cvs.log samba-1.9.16alpha11/source/cvs.log
--- samba-1.9.16alpha10/source/cvs.log Mon Jun 10 15:21:07 1996
+++ samba-1.9.16alpha11/source/cvs.log Thu Jul 18 20:54:26 1996
@@ -1574,3 +1574,822 @@
Log Message:
preparing for release of 1.9.16alpha10
+
+****************************************
+Date: Monday June 10, 1996 @ 16:08
+Author: tridge
+
+Update of /data/cvs/samba/source
+In directory arvidsjaur:/var/tmp/cvs-serv6264
+
+Modified Files:
+ nameannounce.c namedb.c nameelect.c
+Log Message:
+minor patch to allow host announcements to remote subnets
+
+
+
+****************************************
+Date: Wednesday June 12, 1996 @ 11:46
+Author: tridge
+
+Update of /data/cvs/samba/source
+In directory arvidsjaur:/var/tmp/cvs-serv19858
+
+Modified Files:
+ charset.c
+Log Message:
+demo of cvs - ignore
+
+
+
+****************************************
+Date: Friday June 14, 1996 @ 14:20
+Author: samba-bugs
+
+Update of /data/cvs/samba/source
+In directory arvidsjaur:/var/tmp/cvs-serv11409/samba/source
+
+Modified Files:
+ Makefile
+Log Message:
+Added option for specifying awk executable if not 'awk' initially for SunOSxx
+Dan Shearer 14 June 96
+
+
+
+****************************************
+Date: Tuesday June 18, 1996 @ 0:10
+Author: samba-bugs
+
+Update of /data/cvs/samba/source
+In directory arvidsjaur:/var/tmp/cvs-serv9310/samba/source
+
+Modified Files:
+ Makefile mkproto.awk
+Log Message:
+Added source filename to give crude index
+Dan 17 June 1996
+
+
+
+****************************************
+Date: Tuesday June 18, 1996 @ 1:36
+Author: samba-bu
+
+Update of /data/cvs/samba/source
+In directory arvidsjaur:/samba/samba-bugs/samba/source
+
+Modified Files:
+ Makefile
+Log Message:
+Fixed stupid bug introduced minutes ago
+Dan
+
+
+
+****************************************
+Date: Wednesday June 19, 1996 @ 22:23
+Author: tridge
+
+Update of /data/cvs/samba/source
+In directory arvidsjaur:/var/tmp/cvs-serv29445
+
+Modified Files:
+ locking.c printing.c
+Log Message:
+- change date as a demo for john
+- modified plp printing parser to work on my system
+
+
+
+****************************************
+Date: Wednesday June 19, 1996 @ 22:27
+Author: samba-bugs
+
+Update of /data/cvs/samba/source
+In directory arvidsjaur:/var/tmp/cvs-serv29534
+
+Modified Files:
+ smbtar
+Log Message:
+ - deleted reduntant blank line at end of file (JHT)
+
+
+
+****************************************
+Date: Wednesday June 19, 1996 @ 23:23
+Author: samba-bugs
+
+Update of /data/cvs/samba
+In directory arvidsjaur:/var/tmp/cvs-serv30708/samba
+
+Modified Files:
+ README
+Log Message:
+Basic doc changes to keep up to date.
+
+Dan
+
+
+
+****************************************
+Date: Wednesday June 19, 1996 @ 23:23
+Author: samba-bugs
+
+Update of /data/cvs/samba/docs
+In directory arvidsjaur:/var/tmp/cvs-serv30708/samba/docs
+
+Modified Files:
+ announce security_level.txt
+Log Message:
+Basic doc changes to keep up to date.
+
+Dan
+
+
+
+****************************************
+Date: Wednesday June 19, 1996 @ 23:23
+Author: samba-bugs
+
+Update of /data/cvs/samba/source
+In directory arvidsjaur:/var/tmp/cvs-serv30708/samba/source
+
+Modified Files:
+ change-log proto.h system.c
+Log Message:
+Basic doc changes to keep up to date.
+
+Dan
+
+
+
+****************************************
+Date: Sunday June 30, 1996 @ 4:49
+Author: samba-bugs
+
+Update of /data/cvs/samba/source
+In directory arvidsjaur:/var/tmp/cvs-serv13629
+
+Modified Files:
+ Makefile loadparm.c mkproto.awk nameannounce.c namedb.c
+ nameelect.c nameresp.c nameserv.c nameserv.h namework.c nmbd.c
+ nmblookup.c nmbsync.c proto.h smb.h
+Log Message:
+
+
+luke's first attempt at using cvs
+
+accidentally updated the Makefile
+
+updated the name database structure (again!). this time, there is one
+name database per local interface. there is also a pseudo-interface on
+ip 255.255.255.255. its purpose is to store WINS name entries. all the
+local interface name databases store SELF names only. the WINS name
+database stores non-special browser names.
+
+added wins.dat file: records WINS entries in ascii format. this is reloaded
+when nmbd restarts.
+
+added repeating code for response packets. timer is in seconds only at the
+moment.
+
+updated the response queue code to deal with samba registering with a
+WINS server a bit better (added more cases when a response isn't received).
+tidied up the response packet processing code and expire_response_queue()
+code. added cross references between response received and await-response
+expired code.
+
+added over-zealous code that checks all machines that register with samba
+as a WINS server (every 10 minutes i think): to see whether they are still
+alive or not (see rfc1001.txt)
+
+bug reported by terry@ren.pc.athabascau.ca: DNSFAILed names _stay_ as
+DNSFAIL, even though the machine may come back up and REGISTER.
+
+removed update_from_reg() function. it's not necessary, and it does too much.
+
+added code that announces on each local interface samba's ttl as zero and
+servertype as zero when nmbd is kill -TERMed
+
+first attempt at putting the first functionality of samba browsing back in
+(remote subnets should have samba appear in a workgroup specified through
+the lmhosts file)
+
+lots of other miscellaneous tidying up / chopping about.
+
+
+
+****************************************
+Date: Sunday June 30, 1996 @ 5:26
+Author: samba-bugs
+
+Update of /data/cvs/samba/source
+In directory arvidsjaur:/var/tmp/cvs-serv14098/samba/source
+
+Modified Files:
+ Makefile interface.c
+Log Message:
+
+
+added local and remote interfaces (didn't get done in first attempt)
+
+
+
+****************************************
+Date: Sunday June 30, 1996 @ 21:00
+Author: samba-bugs
+
+Update of /data/cvs/samba/source
+In directory arvidsjaur:/var/tmp/cvs-serv9252
+
+Modified Files:
+ Makefile
+Log Message:
+
+
+
+
+****************************************
+Date: Tuesday July 2, 1996 @ 4:22
+Author: samba-bugs
+
+Update of /data/cvs/samba/source
+In directory arvidsjaur:/var/tmp/cvs-serv1723
+
+Added Files:
+ nameresp.doc nameserv.doc
+Log Message:
+
+
+first draft of low-level design documents describing the operation of
+nameserv.c and nameresp.c and their interaction with the rest of nmbd.
+
+
+
+****************************************
+Date: Tuesday July 2, 1996 @ 4:29
+Author: samba-bugs
+
+Update of /data/cvs/samba/source
+In directory arvidsjaur:/var/tmp/cvs-serv1885
+
+Modified Files:
+ nameresp.c nameserv.c proto.h
+Log Message:
+
+
+updated the NetBIOS code due to some bugs found by writing the first draft
+of the low level design docs.
+
+
+
+****************************************
+Date: Tuesday July 2, 1996 @ 4:53
+Author: samba-bugs
+
+Update of /data/cvs/samba/source
+In directory arvidsjaur:/var/tmp/cvs-serv2248
+
+Modified Files:
+ ipc.c
+Log Message:
+
+
+patch to fix NetServerEnum with multiple workgroup lists kindly supplied.
+it works for him. needs testing.
+
+
+
+****************************************
+Date: Wednesday July 3, 1996 @ 1:22
+Author: samba-bugs
+
+Update of /data/cvs/samba/source
+In directory arvidsjaur:/var/tmp/cvs-serv22758
+
+Modified Files:
+ nameresp.doc nameserv.doc
+Added Files:
+ namework.doc
+Log Message:
+
+
+updated low-level design documentation on nmbd. first draft of namework.doc
+and updated the other two.
+
+lkcl
+
+
+
+****************************************
+Date: Wednesday July 3, 1996 @ 1:31
+Author: samba-bugs
+
+Update of /data/cvs/samba/source
+In directory arvidsjaur:/var/tmp/cvs-serv22894
+
+Modified Files:
+ nameserv.c namedb.c Makefile namework.c nameserv.h
+ nameannounce.c nameelect.c nameresp.c
+Added Files:
+ namebrowse.c namelogon.c
+Log Message:
+
+
+as a result of the writing of namework.doc, namework.c has been tidied up,
+some bugs fixed / documented and some discrepancies noted down (in
+namework.c as well as namework.doc)
+
+namebrowse.c and namelogon.c contain functions that were inappropriately
+placed in namework.c. namebrowse.c contains browse sync queue management
+functions that were inappropriately placed in namedb.c
+
+the 'cmd_type' member of response_record has been renamed to 'state'
+because that more accurately reflects it purpose (not entirely. sigh).
+
+fixed a bug in nameserv.c that meant the previous version wouldn't
+compile.
+
+there's probably a bit more...
+
+lkcl
+
+
+
+****************************************
+Date: Wednesday July 3, 1996 @ 11:58
+Author: tridge
+
+Update of /data/cvs/samba/source
+In directory arvidsjaur:/var/tmp/cvs-serv29605
+
+Modified Files:
+ client.c reply.c
+Log Message:
+- moved the protocol defs in the client to keep sill C compilers happy
+- added change for cnum range in reply_tdis()
+
+
+
+****************************************
+Date: Wednesday July 3, 1996 @ 12:39
+Author: tridge
+
+Update of /data/cvs/samba/source
+In directory arvidsjaur:/var/tmp/cvs-serv30677
+
+Modified Files:
+ Makefile proto.h
+Log Message:
+fix Makefile - remove Lukes private stuff :-)
+rerun proto generator
+
+
+
+****************************************
+Date: Wednesday July 3, 1996 @ 12:58
+Author: tridge
+
+Update of /data/cvs/samba/source
+In directory arvidsjaur:/var/tmp/cvs-serv30965
+
+Modified Files:
+ nameannounce.c
+Log Message:
+fixed conflict with global variable updatecount
+
+
+
+****************************************
+Date: Wednesday July 3, 1996 @ 12:58
+Author: tridge
+
+Update of /data/cvs/samba/source
+In directory arvidsjaur:/var/tmp/cvs-serv31015
+
+Modified Files:
+ nameresp.c
+Log Message:
+fixed conflict between two variables called d
+
+
+
+****************************************
+Date: Wednesday July 3, 1996 @ 12:58
+Author: tridge
+
+Update of /data/cvs/samba/source
+In directory arvidsjaur:/var/tmp/cvs-serv31037
+
+Modified Files:
+ proto.h
+Log Message:
+generated new proto.h
+
+
+
+****************************************
+Date: Thursday July 4, 1996 @ 13:16
+Author: samba-bugs
+
+Update of /data/cvs/samba/source
+In directory arvidsjaur:/var/tmp/cvs-serv22778/source
+
+Modified Files:
+ Makefile access.c change-log checkos.sh
+Log Message:
+Started uninstall in Makefile
+Updated some email addresses
+
+
+
+****************************************
+Date: Thursday July 4, 1996 @ 13:22
+Author: samba-bugs
+
+Update of /data/cvs/samba/source
+In directory arvidsjaur:/var/tmp/cvs-serv22827/source
+
+Modified Files:
+ Makefile
+Log Message:
+Put "which awk?" section in Makefile again
+
+Dan
+
+
+
+****************************************
+Date: Friday July 5, 1996 @ 5:19
+Author: samba-bugs
+
+Update of /data/cvs/samba/source
+In directory arvidsjaur:/var/tmp/cvs-serv6347
+
+Modified Files:
+ charset.c ipc.c namedb.c nameelect.c nameresp.c nameserv.c
+ nameserv.h nmbd.c nmbsync.c proto.h
+Log Message:
+
+modified become_master() to a state-based system. becoming a master
+is now performed in stages: wait for each NetBIOS name to be
+successfully registered before proceeding to the next stage.
+
+tied implicit name registration and release (broadcast method) to the
+same piece of code as explicit method (via WINS server).
+
+created special_browser_name() function that checks __MSBROWSE__
+name: this name is ignored by WINS servers apparently.
+
+fixed likely incompatibility between refresh_my_names() and add_my_names().
+(netbios entries were unlikely to be refreshed).
+
+NOTE: none of these changes have been tested. at all.
+
+lkcl
+
+
+
+****************************************
+Date: Friday July 5, 1996 @ 5:40
+Author: samba-bugs
+
+Update of /data/cvs/samba/source
+In directory arvidsjaur:/var/tmp/cvs-serv6805
+
+Modified Files:
+ namebrowse.c proto.h
+Log Message:
+
+namebrowse.c was using variable work uninitialised.
+remkproto'd proto.h
+
+lkcl
+
+
+
+****************************************
+Date: Friday July 5, 1996 @ 11:03
+Author: samba-bugs
+
+Update of /data/cvs/samba/source
+In directory arvidsjaur:/var/tmp/cvs-serv10304/source
+
+Modified Files:
+ Makefile
+Log Message:
+Updated Makefile - removed loadparam.h and friends - not needed??
+
+
+
+****************************************
+Date: Friday July 5, 1996 @ 13:51
+Author: samba-bugs
+
+Update of /data/cvs/samba/source
+In directory arvidsjaur:/var/tmp/cvs-serv12406
+
+Modified Files:
+ Makefile installbin.sh installman.sh installscripts.sh
+Log Message:
+Changed install scripts so they don't have hardcoded values
+
+Dan
+
+
+
+****************************************
+Date: Friday July 5, 1996 @ 13:53
+Author: samba-bugs
+
+Update of /data/cvs/samba/source
+In directory arvidsjaur:/var/tmp/cvs-serv12511
+
+Added Files:
+ uninstallbin.sh uninstallman.sh uninstallscripts.sh
+Log Message:
+Added uninstallation from Makefile, either in parts or total uninstall
+
+Dan
+
+
+
+****************************************
+Date: Saturday July 6, 1996 @ 7:28
+Author: samba-bugs
+
+Update of /data/cvs/samba/source
+In directory arvidsjaur:/var/tmp/cvs-serv28271
+
+Modified Files:
+ Makefile
+Log Message:
+Call checkos in "make proto" in case of OS with broken awk && forgetful user,
+because it looks very much like an awk bug otherwise.
+
+Dan
+
+
+
+****************************************
+Date: Saturday July 6, 1996 @ 7:31
+Author: samba-bugs
+
+Update of /data/cvs/samba/source
+In directory arvidsjaur:/var/tmp/cvs-serv28298
+
+Modified Files:
+ Makefile
+Log Message:
+Change awk to ($AWK) yet again :-)
+
+Dan
+
+
+
+****************************************
+Date: Sunday July 7, 1996 @ 22:36
+Author: samba-bugs
+
+Update of /data/cvs/samba/source
+In directory arvidsjaur:/var/tmp/cvs-serv28811
+
+Modified Files:
+ Makefile nameannounce.c namebrowse.c nameelect.c nameresp.c
+ nameresp.doc nameserv.c nameserv.doc nameserv.h namework.c
+ namework.doc
+Added Files:
+ nameannounce.doc namebrowse.doc namedbname.doc namedbresp.doc
+ nameelect.doc namelogon.doc namepacket.doc namequery.doc
+ nameservreply.doc nameservresp.doc
+Log Message:
+
+
+tidied up: code shuffling and documentation.
+created namedb*.c nameservresp.c nameservreply.c and namepacket.c
+added modules to Makefile, downloading dan's current version first :-)
+shuffled docs to match source
+created more docs
+
+fixed bug in announce_backup() discovered when going nameannounce.doc:
+backup list requests to the master browser should be used when samba is
+not a master browser; backup list requests to the primary domain
+controller should be used when samba is not a primary domain controller.
+
+fixed bug in sync_server: it would never send MasterAnnounce packets.
+
+removed the code that ignored special browser names: these should only
+be ignored (except 0x1b names) when broadcasted name queries are sent,
+not when directed registration or directed queries are sent samba as a
+WINS server. (note: exactly what's going on is still uncertain).
+
+renamed NAME_QUERY_MST_SRV_CHK to NAME_QUERY_PDC_SRV_CHK (more accurate).
+renamed NAME_STATUS_MST_SRV_CHK to NAME_STATUS_PDC_SRV_CHK (more accurate).
+
+added secured WINS name registration: a new 'state' NAME_REGISTER_CHALLENGE;
+functions send_name_response(), response_name_query_register(); added
+sending of WAIT ACKNOWLEDGEMENT packet; added a reply_to_ip field to
+the response record structure so that after the name query challenge,
+you know who to inform of the outcome of that challenge.
+
+note: these are all currently untested modifications (yikes!)
+
+lkcl
+
+
+
+****************************************
+Date: Sunday July 7, 1996 @ 23:29
+Author: samba-bugs
+
+Update of /data/cvs/samba/source
+In directory arvidsjaur:/var/tmp/cvs-serv29341
+
+Modified Files:
+ Makefile namedb.c proto.h
+Added Files:
+ namedbname.c namedbresp.c namedbserver.c namedbsubnet.c
+ namedbwork.c namepacket.c nameservreply.c nameservresp.c
+Log Message:
+
+added the recently shuffled and updated source files missed in the
+previous commit (see previous log message for details)
+
+fixed bug in nameservreply.c: wrong macro in use (RSSVAL not IVAL!).
+
+did another make proto
+
+lkcl
+
+
+
+****************************************
+Date: Wednesday July 10, 1996 @ 4:01
+Author: samba-bugs
+
+Update of /data/cvs/samba/source
+In directory arvidsjaur:/var/tmp/cvs-serv9536
+
+Modified Files:
+ nameannounce.c namedbname.c namedbresp.c namedbserver.c
+ namedbsubnet.c namedbwork.c nameelect.c namepacket.c
+ nameresp.c nameserv.c namework.c
+Log Message:
+
+sorted out various timer delay bugs: nameannounce.c nameserv.c
+
+namedbname.c:search_for_name() wasn't looking for 0x1b as well as
+0x0 and 0x20 name types.
+
+reduced number of retransmissions of packets from 4 to 3 times.
+
+added code that ensures remote lmhosts entries don't get deleted when
+a master browser cannot be found on a remote subnet. stopped forcing
+an election on remote subnets if a master browser cannot be found.
+
+stopped browse list and wins list from being written out too frequently.
+
+only add samba's names to local interfaces.
+
+add 0x1c name if we are a domain logon machine (needs more exploration).
+
+why bother reloading services when receiving a SIGTERM?
+
+sort out add_my_name_entry() and remove_name_entry() to deal with
+broadcast, samba as a WINS and samba using a WINS. properly.
+
+added extra debug information to help with expected response queue code.
+updated debug comments in become_master().
+
+altered dump_names() DEBUG format. it looks prettier.
+altered wins.dat format to match DEBUG format.
+
+lkcl
+
+
+
+****************************************
+Date: Wednesday July 10, 1996 @ 4:11
+Author: samba-bugs
+
+Update of /data/cvs/samba/source
+In directory arvidsjaur:/var/tmp/cvs-serv9831
+
+Modified Files:
+ nmbd.c proto.h
+Log Message:
+
+missed nmbd.c in previous update.
+did a make proto
+
+lkcl
+
+
+
+****************************************
+Date: Thursday July 11, 1996 @ 4:48
+Author: samba-bugs
+
+Update of /data/cvs/samba/source
+In directory arvidsjaur:/var/tmp/cvs-serv29974
+
+Modified Files:
+ ipc.c namedbresp.doc namedbsubnet.c nameelect.c nameelect.doc
+ nameresp.c nameserv.c nameserv.doc nameservreply.c
+ nameservreply.doc nameservresp.c nameservresp.doc proto.h
+Removed Files:
+ namedb.c
+Log Message:
+
+updated docs to match code mods from last two or three updates. done
+some more commenting of code to match docs.
+
+sorted some bugs.
+
+ipc BOOL domains was uninitialised.
+
+lkcl
+
+
+
+****************************************
+Date: Thursday July 11, 1996 @ 23:55
+Author: samba-bugs
+
+Update of /data/cvs/samba/examples/simple
+In directory arvidsjaur:/var/tmp/cvs-serv7090
+
+Modified Files:
+ smb.conf
+Log Message:
+Modified demo smb.conf to not have /tmp writeable by everyone by default.
+According to server-linux some people seem to be uncommenting the example
+[tmp] without thinking what it does :-)
+
+Dan
+
+
+
+****************************************
+Date: Thursday July 18, 1996 @ 4:33
+Author: samba-bugs
+
+Update of /data/cvs/samba/source
+In directory arvidsjaur:/var/tmp/cvs-serv28303
+
+Modified Files:
+ client.c ipc.c nameannounce.c namedbname.c namedbserver.c
+ nameelect.c namepacket.c namequery.c nameresp.c nameresp.doc
+ nameserv.c nameserv.h nameservreply.c nameservresp.c
+ namework.c nmbd.c nmblookup.c proto.h version.h
+Log Message:
+
+lots of changes to nmbd
+
+lkcl
+
+
+
+****************************************
+Date: Thursday July 18, 1996 @ 20:08
+Author: tridge
+
+Update of /data/cvs/samba/source
+In directory arvidsjaur:/var/tmp/cvs-serv11425
+
+Modified Files:
+ client.c
+Log Message:
+removed some debug stuff from luke
+
+
+
+****************************************
+Date: Thursday July 18, 1996 @ 20:20
+Author: tridge
+
+Update of /data/cvs/samba/source
+In directory arvidsjaur:/var/tmp/cvs-serv11854
+
+Modified Files:
+ Makefile includes.h namework.c proto.h smb.h smbpass.c
+Log Message:
+minor cleanups ready for another release
+
+
+
+
+****************************************
+Date: Thursday July 18, 1996 @ 20:53
+Author: samba-bu
+
+Update of /data/cvs/samba/source
+In directory arvidsjaur:/samba/samba-bugs/samba/source
+
+Modified Files:
+ version.h
+Log Message:
+preparing for release of 1.9.16alpha11
+
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/includes.h samba-1.9.16alpha11/source/includes.h
--- samba-1.9.16alpha10/source/includes.h Thu Jun 6 21:57:20 1996
+++ samba-1.9.16alpha11/source/includes.h Thu Jul 18 20:53:15 1996
@@ -984,9 +984,6 @@
#include "nameserv.h"
#include "proto.h"
#include "byteorder.h"
-#ifdef SMB_PASSWD
-#include "smbpass.h"
-#endif
#include "kanji.h"
#include "charset.h"
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/installbin.sh samba-1.9.16alpha11/source/installbin.sh
--- samba-1.9.16alpha10/source/installbin.sh Sat May 4 17:50:25 1996
+++ samba-1.9.16alpha11/source/installbin.sh Mon Jul 15 17:55:03 1996
@@ -34,7 +34,9 @@
cat << EOF
======================================================================
The binaries are installed. You may restore the old binaries (if there
-were any) using the command "make revert"
+were any) using the command "make revert". You may uninstall the binaries
+using the command "make uninstallbin" or "make uninstall" to uninstall
+binaries, man pages and shell scripts.
======================================================================
EOF
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/installman.sh samba-1.9.16alpha11/source/installman.sh
--- samba-1.9.16alpha10/source/installman.sh Sat May 4 17:50:25 1996
+++ samba-1.9.16alpha11/source/installman.sh Mon Jul 15 17:55:03 1996
@@ -1,4 +1,6 @@
#!/bin/sh
+#5 July 96 Dan.Shearer@unisa.edu.au removed hardcoded values
+
MANDIR=$1
SRCDIR=$2
@@ -8,28 +10,29 @@
if [ ! -d $d ]; then
mkdir $d
if [ ! -d $d ]; then
- echo Failed to make directory $d
+ echo Failed to make directory $d, does $USER have privileges?
exit 1
fi
fi
done
-cp $SRCDIR../docs/*.1 $MANDIR/man1
-cp $SRCDIR../docs/*.5 $MANDIR/man5
-cp $SRCDIR../docs/*.8 $MANDIR/man8
-cp $SRCDIR../docs/*.7 $MANDIR/man7
-echo Setting permissions on man pages
-chmod 0644 $MANDIR/man1/smbstatus.1
-chmod 0644 $MANDIR/man1/smbclient.1
-chmod 0644 $MANDIR/man1/smbrun.1
-chmod 0644 $MANDIR/man1/testparm.1
-chmod 0644 $MANDIR/man1/testprns.1
-chmod 0644 $MANDIR/man1/smbtar.1
-chmod 0644 $MANDIR/man5/smb.conf.5
-chmod 0644 $MANDIR/man7/samba.7
-chmod 0644 $MANDIR/man8/smbd.8
-chmod 0644 $MANDIR/man8/nmbd.8
+for sect in 1 5 7 8 ; do
+ for m in $MANDIR/man$sect ; do
+ for s in $SRCDIR../docs/*$sect; do
+ FNAME=$m/`basename $s`
+ cp $s $m || echo Cannot create $FNAME... does $USER have privileges?
+ chmod 0644 $FNAME
+ done
+ done
+done
+
+cat << EOF
+======================================================================
+The man pages have been installed. You may uninstall them using the command
+the command "make uninstallman" or make "uninstall" to uninstall binaries,
+man pages and shell scripts.
+======================================================================
+EOF
-echo Man pages installed
exit 0
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/installscripts.sh samba-1.9.16alpha11/source/installscripts.sh
--- samba-1.9.16alpha10/source/installscripts.sh Sat Jun 8 15:37:52 1996
+++ samba-1.9.16alpha11/source/installscripts.sh Mon Jul 15 17:55:03 1996
@@ -1,26 +1,43 @@
#!/bin/sh
# this script courtesy of James_K._Foote.PARC@xerox.com
+# 5 July 96 Dan.Shearer@UniSA.Edu.Au Don't hardcode script names, get from Make
+
INSTALLPERMS=$1
BINDIR=$2
-SRCDIR=$3
+
+shift
+shift
echo Installing scripts in $BINDIR
-for d in $BINDIR; do
+for d in [ $BINDIR ]; do
if [ ! -d $d ]; then
mkdir $d
if [ ! -d $d ]; then
echo Failed to make directory $d
+ echo Have you run installbin first?
exit 1
fi
fi
done
-cp ${SRCDIR}smbtar $BINDIR
-cp ${SRCDIR}addtosmbpass $BINDIR
-echo Setting permissions on scripts
-chmod $INSTALLPERMS $BINDIR/smbtar
-chmod $INSTALLPERMS $BINDIR/addtosmbpass
+for p in $*; do
+ echo Installing $BINDIR/$p
+ cp $p $BINDIR/$p
+ if [ ! -f $BINDIR/$p ]; then
+ echo Cannot copy $p... does $USER have privileges?
+ fi
+ echo Setting permissions on $BINDIR/$p
+ chmod $INSTALLPERMS $BINDIR/$p
+done
+
+cat << EOF
+======================================================================
+The scripts have been installed. You may uninstall them using
+the command "make uninstallscripts" or "make install" to install binaries,
+man pages and shell scripts. You may recover the previous version (if any
+by "make revert".
+======================================================================
+EOF
-echo Scripts installed
exit 0
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/interface.c samba-1.9.16alpha11/source/interface.c
--- samba-1.9.16alpha10/source/interface.c Mon Jun 10 15:18:51 1996
+++ samba-1.9.16alpha11/source/interface.c Sun Jun 30 15:17:24 1996
@@ -32,12 +32,9 @@
static BOOL got_bcast=False;
static BOOL got_nmask=False;
-static struct interface {
- struct interface *next;
- struct in_addr ip;
- struct in_addr bcast;
- struct in_addr nmask;
-} *interfaces = NULL;
+struct interface *local_interfaces = NULL;
+struct interface *remote_interfaces = NULL;
+
struct interface *last_iface;
/****************************************************************************
@@ -253,13 +250,12 @@
-
/****************************************************************************
load a list of network interfaces
****************************************************************************/
-void load_interfaces(void)
+static void interpret_interfaces(char *s, struct interface **interfaces,
+ char *description)
{
- char *s = lp_interfaces();
char *ptr = s;
fstring token;
struct interface *iface;
@@ -278,7 +274,7 @@
/* maybe we already have it listed */
{
struct interface *i;
- for (i=interfaces;i;i=i->next)
+ for (i=(*interfaces);i;i=i->next)
if (ip_equal(ip,i->ip)) break;
if (i) continue;
}
@@ -299,18 +295,18 @@
iface->bcast.s_addr = iface->ip.s_addr | ~iface->nmask.s_addr;
iface->next = NULL;
- if (!interfaces) {
- interfaces = iface;
+ if (!(*interfaces)) {
+ (*interfaces) = iface;
} else {
last_iface->next = iface;
}
last_iface = iface;
- DEBUG(1,("Added interface ip=%s ",inet_ntoa(iface->ip)));
+ DEBUG(1,("Added %s ip=%s ",description,inet_ntoa(iface->ip)));
DEBUG(1,("bcast=%s ",inet_ntoa(iface->bcast)));
DEBUG(1,("nmask=%s\n",inet_ntoa(iface->nmask)));
}
- if (interfaces) return;
+ if (*interfaces) return;
/* setup a default interface */
iface = (struct interface *)malloc(sizeof(*iface));
@@ -339,7 +335,7 @@
DEBUG(2,("Warning: inconsistant interface %s\n",inet_ntoa(iface->ip)));
}
- interfaces = last_iface = iface;
+ (*interfaces) = last_iface = iface;
DEBUG(1,("Added interface ip=%s ",inet_ntoa(iface->ip)));
DEBUG(1,("bcast=%s ",inet_ntoa(iface->bcast)));
@@ -348,6 +344,21 @@
/****************************************************************************
+load the remote and local interfaces
+****************************************************************************/
+void load_interfaces(void)
+{
+ /* add the machine's interfaces to local interface structure*/
+ interpret_interfaces(lp_interfaces (), &local_interfaces,
+ "interface");
+
+ /* add all subnets to remote interfaces structure */
+ interpret_interfaces(lp_remote_interfaces(), &remote_interfaces,
+ "remote subnet");
+}
+
+
+/****************************************************************************
override the defaults
**************************************************************************/
void iface_set_default(char *ip,char *bcast,char *nmask)
@@ -375,7 +386,7 @@
BOOL ismyip(struct in_addr ip)
{
struct interface *i;
- for (i=interfaces;i;i=i->next)
+ for (i=local_interfaces;i;i=i->next)
if (ip_equal(i->ip,ip)) return True;
return False;
}
@@ -386,7 +397,7 @@
BOOL ismybcast(struct in_addr bcast)
{
struct interface *i;
- for (i=interfaces;i;i=i->next)
+ for (i=local_interfaces;i;i=i->next)
if (ip_equal(i->bcast,bcast)) return True;
return False;
}
@@ -399,7 +410,7 @@
int ret = 0;
struct interface *i;
- for (i=interfaces;i;i=i->next)
+ for (i=local_interfaces;i;i=i->next)
ret++;
return ret;
}
@@ -411,7 +422,7 @@
{
struct interface *i;
- for (i=interfaces;i && n;i=i->next)
+ for (i=local_interfaces;i && n;i=i->next)
n--;
if (i) return &i->ip;
@@ -421,15 +432,14 @@
static struct interface *iface_find(struct in_addr ip)
{
struct interface *i;
- if (zero_ip(ip)) return interfaces;
+ if (zero_ip(ip)) return local_interfaces;
- for (i=interfaces;i;i=i->next)
+ for (i=local_interfaces;i;i=i->next)
if (same_net(i->ip,ip,i->nmask)) return i;
- return interfaces;
+ return local_interfaces;
}
-
/* these 3 functions return the ip/bcast/nmask for the interface
most appropriate for the given ip address */
@@ -447,5 +457,6 @@
{
return(&iface_find(ip)->ip);
}
+
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/loadparm.c samba-1.9.16alpha11/source/loadparm.c
--- samba-1.9.16alpha10/source/loadparm.c Mon Jun 10 15:18:53 1996
+++ samba-1.9.16alpha11/source/loadparm.c Sun Jun 30 15:17:25 1996
@@ -129,6 +129,7 @@
char *szSmbrun;
char *szWINSserver;
char *szInterfaces;
+ char *szRemoteInterfaces;
int max_log_size;
int mangled_stack;
int max_xmit;
@@ -366,6 +367,7 @@
{"null passwords", P_BOOL, P_GLOBAL, &Globals.bNullPasswords, NULL},
{"strip dot", P_BOOL, P_GLOBAL, &Globals.bStripDot, NULL},
{"interfaces", P_STRING, P_GLOBAL, &Globals.szInterfaces, NULL},
+ {"remote interfaces",P_STRING, P_GLOBAL, &Globals.szRemoteInterfaces,NULL},
{"password server", P_STRING, P_GLOBAL, &Globals.szPasswordServer, NULL},
{"socket options", P_GSTRING, P_GLOBAL, user_socket_options, NULL},
{"smbrun", P_STRING, P_GLOBAL, &Globals.szSmbrun, NULL},
@@ -704,6 +706,7 @@
FN_GLOBAL_STRING(lp_logon_script,&Globals.szLogonScript)
FN_GLOBAL_STRING(lp_wins_server,&Globals.szWINSserver)
FN_GLOBAL_STRING(lp_interfaces,&Globals.szInterfaces)
+FN_GLOBAL_STRING(lp_remote_interfaces,&Globals.szRemoteInterfaces)
FN_GLOBAL_BOOL(lp_wins_support,&Globals.bWINSsupport)
FN_GLOBAL_BOOL(lp_wins_proxy,&Globals.bWINSproxy)
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/locking.c samba-1.9.16alpha11/source/locking.c
--- samba-1.9.16alpha10/source/locking.c Mon Jun 10 15:18:54 1996
+++ samba-1.9.16alpha11/source/locking.c Sun Jun 30 15:17:25 1996
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
Locking functions
- Copyright (C) Andrew Tridgell 1992-1995
+ Copyright (C) Andrew Tridgell 1992-1996
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/mkproto.awk samba-1.9.16alpha11/source/mkproto.awk
--- samba-1.9.16alpha10/source/mkproto.awk Mon Jun 10 15:18:54 1996
+++ samba-1.9.16alpha11/source/mkproto.awk Sun Jun 30 15:17:25 1996
@@ -1,13 +1,17 @@
-# generate prototypes for Samba C code
-# tridge, June 1996
-
BEGIN {
inheader=0;
+ current_file="";
print "/* This file is automatically generated with \"make proto\". DO NOT EDIT */"
print ""
}
{
+ if (FILENAME!=current_file) {
+ print ""
+ print "/*The following definitions come from ",FILENAME," */"
+ print ""
+ current_file=FILENAME
+ }
if (inheader) {
if (match($0,"[)][ \t]*$")) {
inheader = 0;
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/nameannounce.c samba-1.9.16alpha11/source/nameannounce.c
--- samba-1.9.16alpha10/source/nameannounce.c Mon Jun 10 15:18:55 1996
+++ samba-1.9.16alpha11/source/nameannounce.c Thu Jul 18 20:53:15 1996
@@ -48,9 +48,7 @@
extern int updatecount;
extern int workgroup_count;
-/* what server type are we currently */
-
-#define BROWSE_MAILSLOT "\\MAILSLOT\\BROWSE"
+extern struct in_addr ipgrp;
/****************************************************************************
send a announce request to the local net
@@ -72,12 +70,16 @@
CVAL(p,0) = ANN_AnnouncementRequest;
p++;
- CVAL(p,0) = work->token; /* flags?? XXXX probably a token*/
+ CVAL(p,0) = work->token; /* (local) unique workgroup token id */
p++;
StrnCpy(p,myname,16);
strupper(p);
p = skip_string(p,1);
+ /* XXXX note: if we sent the announcement request to 0x1d instead
+ of 0x1e, then we could get the master browser to announce to
+ us instead of the members of the workgroup. wha-hey! */
+
send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
myname,work->work_group,0x20,0x1e,ip,*iface_ip(ip));
}
@@ -109,8 +111,32 @@
myname,to_name,from,to,dest_ip,*iface_ip(dest_ip));
}
+
+/****************************************************************************
+ find a server responsible for a workgroup, and sync browse lists
+ control ends up back here via response_name_query.
+ **************************************************************************/
+void sync_server(enum state_type state, char *serv_name, char *work_name,
+ int name_type,
+ struct in_addr ip)
+{
+ add_browser_entry(serv_name, name_type, work_name, 0, ip);
+
+ if (state == NAME_STATUS_PDC_SRV_CHK)
+ {
+ /* announce ourselves as a master browser to serv_name */
+ do_announce_request(myname, serv_name, ANN_MasterAnnouncement,
+ 0x20, 0, ip);
+ }
+}
+
+
/****************************************************************************
construct a host announcement unicast
+
+ this function should not be used heavily, and only when we are _not_
+ a master browser and _not_ a primary domain controller.
+
**************************************************************************/
void announce_backup(void)
{
@@ -120,11 +146,19 @@
char *p;
struct subnet_record *d1;
int tok;
+ static uint32 id_count = 0;
if (!lastrun) lastrun = t;
- if (t < lastrun + CHECK_TIME_ANNOUNCE_BACKUP * 60) return;
+#if 1
+ if (t < lastrun + 1 * 60)
+#else
+ if (t < lastrun + CHECK_TIME_ANNOUNCE_BACKUP * 60)
+#endif
+ return;
lastrun = t;
+ DEBUG(4,("checking backups...\n"));
+
for (tok = 0; tok <= workgroup_count; tok++)
{
for (d1 = subnetlist; d1; d1 = d1->next)
@@ -139,18 +173,11 @@
if (!work) continue;
+ if (AM_MASTER(work) && AM_DOMCTL(work)) continue;
+
/* found one: announce it across all domains */
for (d = subnetlist; d; d = d->next)
{
- int type=0;
-
- if (AM_DOMCTL(work)) {
- type = 0x1b;
- } else if (AM_MASTER(work)) {
- type = 0x1d;
- } else {
- continue;
- }
DEBUG(2,("sending announce backup %s workgroup %s(%d)\n",
inet_ntoa(d->bcast_ip),work->work_group,
@@ -158,20 +185,42 @@
bzero(outbuf,sizeof(outbuf));
p = outbuf;
+
CVAL(p,0) = ANN_GetBackupListReq;
- p++;
-
- CVAL(p,0) = 1; /* count? */
- SIVAL(p,1,work->token); /* workgroup unique key index */
- p += 5;
- p++;
+ CVAL(p,1) = work->token; /* workgroup unique key index */
+ SIVAL(p,2,++id_count); /* unique count. not that we use it! */
+
+ p += 6;
- send_mailslot_reply(BROWSE_MAILSLOT,
+ debug_browse_data(outbuf, PTR_DIFF(p,outbuf));
+
+ if (!AM_DOMCTL(work))
+ {
+ /* only ask for a list of backup domain controllers
+ if we are not a domain controller ourselves */
+
+ send_mailslot_reply(BROWSE_MAILSLOT,
ClientDGRAM,outbuf,
PTR_DIFF(p,outbuf),
myname, work->work_group,
- 0x0,type,d->bcast_ip,
+ 0x0,0x1b,d->bcast_ip,
*iface_ip(d->bcast_ip));
+ }
+
+ debug_browse_data(outbuf, PTR_DIFF(p,outbuf));
+
+ if (!AM_MASTER(work))
+ {
+ /* only ask for a list of master browsers if we
+ are not a master browser ourselves */
+
+ send_mailslot_reply(BROWSE_MAILSLOT,
+ ClientDGRAM,outbuf,
+ PTR_DIFF(p,outbuf),
+ myname, work->work_group,
+ 0x0,0x1d,d->bcast_ip,
+ *iface_ip(d->bcast_ip));
+ }
}
}
}
@@ -179,19 +228,132 @@
/****************************************************************************
+ send a host announcement packet
+ **************************************************************************/
+static void do_announce_host(int command,
+ char *from_name, int from_type, struct in_addr from_ip,
+ char *to_name , int to_type , struct in_addr to_ip,
+ time_t announce_interval,
+ char *server_name, int server_type, char *server_comment)
+{
+ pstring outbuf;
+ char *p;
+
+ bzero(outbuf,sizeof(outbuf));
+ p = outbuf+1;
+
+ /* command type */
+ CVAL(outbuf,0) = command;
+
+ /* announcement parameters */
+ CVAL(p,0) = updatecount;
+ SIVAL(p,1,announce_interval*1000); /* ms - despite the spec */
+
+ StrnCpy(p+5,server_name,16);
+ strupper(p+5);
+
+ CVAL(p,21) = 0x02; /* major version */
+ CVAL(p,22) = 0x02; /* minor version */
+
+ SIVAL(p,23,server_type);
+ SSVAL(p,27,0x010f); /* browse version: got from NT/AS 4.00 */
+ SSVAL(p,29,0xaa55); /* browse signature */
+
+ strcpy(p+31,server_comment);
+ p += 31;
+ p = skip_string(p,1);
+
+ debug_browse_data(outbuf, PTR_DIFF(p,outbuf));
+
+ /* send the announcement */
+ send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,
+ PTR_DIFF(p,outbuf),
+ from_name, to_name,
+ from_type, to_type,
+ to_ip, from_ip);
+}
+
+
+/****************************************************************************
+ remove all samba's server entries
+ ****************************************************************************/
+void remove_my_servers(void)
+{
+ struct subnet_record *d;
+ for (d = subnetlist; d; d = d->next)
+ {
+ struct work_record *work;
+ for (work = d->workgrouplist; work; work = work->next)
+ {
+ struct server_record *s;
+ for (s = work->serverlist; s; s = s->next)
+ {
+ if (!strequal(myname,s->serv.name)) continue;
+ announce_server(d, work, s->serv.name, s->serv.comment, 0, 0);
+ }
+ }
+ }
+}
+
+
+/****************************************************************************
+ announce a server entry
+ ****************************************************************************/
+void announce_server(struct subnet_record *d, struct work_record *work,
+ char *name, char *comment, time_t ttl, int server_type)
+{
+ uint32 domain_type = SV_TYPE_DOMAIN_ENUM|SV_TYPE_SERVER_UNIX;
+
+ if (AM_MASTER(work))
+ {
+ DEBUG(3,("sending local master announce to %s for %s(1e)\n",
+ inet_ntoa(d->bcast_ip),work->work_group));
+
+ do_announce_host(ANN_LocalMasterAnnouncement,
+ name , 0x00, d->myip,
+ work->work_group, 0x1e, d->bcast_ip,
+ ttl*1000,
+ name, server_type, comment);
+
+ DEBUG(3,("sending domain announce to %s for %s\n",
+ inet_ntoa(d->bcast_ip),work->work_group));
+
+ /* XXXX should we do a domain-announce-kill? */
+ if (server_type != 0)
+ {
+ if (AM_DOMCTL(work)) {
+ domain_type |= SV_TYPE_DOMAIN_CTRL;
+ }
+ do_announce_host(ANN_DomainAnnouncement,
+ name , 0x00, d->myip,
+ MSBROWSE, 0x01, d->bcast_ip,
+ ttl*1000,
+ work->work_group, server_type ? domain_type : 0,
+ comment);
+ }
+ }
+ else
+ {
+ DEBUG(3,("sending host announce to %s for %s(1d)\n",
+ inet_ntoa(d->bcast_ip),work->work_group));
+
+ do_announce_host(ANN_HostAnnouncement,
+ name , 0x00, d->myip,
+ work->work_group, 0x1d, d->bcast_ip,
+ ttl*1000,
+ name, server_type, comment);
+ }
+}
+
+/****************************************************************************
construct a host announcement unicast
**************************************************************************/
void announce_host(void)
{
time_t t = time(NULL);
- pstring outbuf;
- char *p;
- char *namep;
- char *stypep;
- char *commentp;
+ struct subnet_record *d;
pstring comment;
char *my_name;
- struct subnet_record *d;
StrnCpy(comment, *ServerComment ? ServerComment : "NoComment", 43);
@@ -201,8 +363,7 @@
{
struct work_record *work;
- if (!d->my_interface)
- continue;
+ if (ip_equal(d->bcast_ip, ipgrp)) continue;
for (work = d->workgrouplist; work; work = work->next)
{
@@ -210,11 +371,16 @@
struct server_record *s;
BOOL announce = False;
+ /* must work on the code that does announcements at up to
+ 30 seconds later if a master browser sends us a request
+ announce.
+ */
+
if (work->needannounce) {
/* drop back to a max 3 minute announce - this is to prevent a
single lost packet from stuffing things up for too long */
- work->announce_interval = MIN(work->announce_interval,
- CHECK_TIME_MIN_HOST_ANNCE*60);
+ work->announce_interval = MIN(work->announce_interval,
+ CHECK_TIME_MIN_HOST_ANNCE*60);
work->lastannounce_time = t - (work->announce_interval+1);
}
@@ -242,85 +408,18 @@
}
if (announce)
- {
- bzero(outbuf,sizeof(outbuf));
- p = outbuf+1;
-
- CVAL(p,0) = updatecount;
- /* ms - despite the spec */
- SIVAL(p,1,work->announce_interval*1000);
- namep = p+5;
- StrnCpy(namep,my_name,16);
- strupper(namep);
- CVAL(p,21) = 2; /* major version */
- CVAL(p,22) = 2; /* minor version */
- stypep = p+23;
- SIVAL(p,23,stype);
- SSVAL(p,27,0xaa55); /* browse signature */
- SSVAL(p,29,1); /* browse version */
- commentp = p+31;
- strcpy(commentp,comment);
- p = p+31;
- p = skip_string(p,1);
-
- if (d->my_interface)
- {
- if (AM_MASTER(work))
- {
- SIVAL(stypep,0,work->ServerType);
-
- DEBUG(2,("sending local master announce to %s for %s\n",
- inet_ntoa(d->bcast_ip),work->work_group));
-
- CVAL(outbuf,0) = ANN_LocalMasterAnnouncement;
-
- send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,
- PTR_DIFF(p,outbuf),
- my_name,work->work_group,0,
- 0x1e,d->bcast_ip,
- *iface_ip(d->bcast_ip));
-
- DEBUG(2,("sending domain announce to %s for %s\n",
- inet_ntoa(d->bcast_ip),work->work_group));
-
- CVAL(outbuf,0) = ANN_DomainAnnouncement;
-
- StrnCpy(namep,work->work_group,15);
- strupper(namep);
- StrnCpy(commentp,myname,15);
- strupper(commentp);
-
- SIVAL(stypep,0,(unsigned)0x80000000);
- p = commentp + strlen(commentp) + 1;
-
- send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,
- PTR_DIFF(p,outbuf),
- my_name,MSBROWSE,0,0x01,d->bcast_ip,
- *iface_ip(d->bcast_ip));
- }
- else
- {
- DEBUG(2,("sending host announce to %s for %s\n",
- inet_ntoa(d->bcast_ip),work->work_group));
-
- CVAL(outbuf,0) = ANN_HostAnnouncement;
-
- send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,
- PTR_DIFF(p,outbuf),
- my_name,work->work_group,0,0x1d,
- d->bcast_ip,*iface_ip(d->bcast_ip));
- }
- }
- }
+ {
+ announce_server(d,work,my_name,comment,work->announce_interval,stype);
+ }
if (work->needannounce)
- {
+ {
work->needannounce = False;
break;
/* sorry: can't do too many announces. do some more later */
- }
+ }
}
- }
+ }
}
@@ -332,7 +431,7 @@
least 15 minutes.
this actually gets done in search_and_sync_workgroups() via the
- MASTER_SERVER_CHECK command, if there is a response from the
+ NAME_QUERY_PDC_SRV_CHK command, if there is a response from the
name query initiated here. see response_name_query()
**************************************************************************/
void announce_master(void)
@@ -342,8 +441,9 @@
time_t t = time(NULL);
BOOL am_master = False; /* are we a master of some sort? :-) */
- if (last && (t-last < CHECK_TIME_MST_ANNOUNCE * 60))
- return;
+ if (!last) last = t;
+ if (t-last < CHECK_TIME_MST_ANNOUNCE * 60)
+ return;
last = t;
@@ -386,20 +486,20 @@
struct in_addr ip;
ip = ipzero;
- queue_netbios_pkt_wins(ClientNMB,NMB_QUERY,
- MASTER_SERVER_CHECK,
- work->work_group,0x1b,0,
- False, False, ip);
+ queue_netbios_pkt_wins(d,ClientNMB,NMB_QUERY,
+ NAME_QUERY_PDC_SRV_CHK,
+ work->work_group,0x1b,0,0,
+ False, False, ip, ip);
}
else
{
struct subnet_record *d2;
for (d2 = subnetlist; d2; d2 = d2->next)
{
- queue_netbios_packet(ClientNMB,NMB_QUERY,
- MASTER_SERVER_CHECK,
- work->work_group,0x1b,0,
- True, False, d2->bcast_ip);
+ queue_netbios_packet(d,ClientNMB,NMB_QUERY,
+ NAME_QUERY_PDC_SRV_CHK,
+ work->work_group,0x1b,0,0,
+ True, False, d2->bcast_ip, d2->bcast_ip);
}
}
}
@@ -431,9 +531,9 @@
/* check the existence of a pdc for this workgroup, and if
one exists at the specified ip, sync with it and announce
ourselves as a master browser to it */
- queue_netbios_pkt_wins(ClientNMB, NMB_QUERY,MASTER_SERVER_CHECK,
- work->work_group,0x1b, 0,
- bcast, False, ip);
+ queue_netbios_pkt_wins(d,ClientNMB, NMB_QUERY,NAME_QUERY_PDC_SRV_CHK,
+ work->work_group,0x1b, 0, 0,
+ bcast, False, ip, ip);
}
}
}
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/nameannounce.doc samba-1.9.16alpha11/source/nameannounce.doc
--- samba-1.9.16alpha10/source/nameannounce.doc Thu Jan 1 10:00:00 1970
+++ samba-1.9.16alpha11/source/nameannounce.doc Sun Jul 7 22:35:54 1996
@@ -0,0 +1,137 @@
+this module deals with announcements: the sending of announcement requests
+and the sending of announcements either to refresh other servers' records
+or as a response to announcement requests.
+
+
+/*************************************************************************
+ announce_master()
+ *************************************************************************/
+
+this function is responsible for announcing samba as a master browser
+to all known primary domain controllers.
+
+this announcement is sent out at CHECK_TIME_MST_ANNOUNCE minute
+intervals, only if samba is a master browser on one or more of
+its local interfaces.
+
+if no domain controller has been specified (lp_domain_controller())
+samba goes through its list of servers looking for primary domain
+controllers. when it finds one (other than itself) it will either
+initiate a NAME_QUERY_PDC_SRV_CHK by broadcast or with a WINS
+server. this will result in a NAME_STATUS_PDC_SRV_CHK, which
+will result in a sync browse list and an announcement
+ANN_MasterAnnounce being sent (see sync_server()).
+
+if a domain controller has been specified, samba will search for
+a primary domain controller for its workgroup (either by directed
+packet or by broadcast if it cannot resolve the domain controller
+name using DNS), which results in the same action as listed above.
+
+
+/*************************************************************************
+ announce_host()
+ *************************************************************************/
+
+this complex-looking function is responsible for announcing samba's
+existence to other servers by broadcast. the actual announcement
+is carried out by announce_server().
+
+the time period between samba's announcement will stretch from one
+minute to twelve minutes by one minute. if samba has received an
+announce request from a master browser, then it should answer at
+any random interval between zero and thirty seconds after the
+request is received. this is to ensure that the master browser
+does not get overloaded with responses!
+
+
+/*************************************************************************
+ announce_server()
+ *************************************************************************/
+
+this function is responsible for sending announcement packets.
+these packets are received by other servers, which will then
+update their records accordingly: what services we have, our
+name, our comment field and our time to live (to name a few).
+
+if we are a master browser, then using do_announce_host() we
+must send an announcement notifying members of that workgroup
+that we are their master browser, and another announcement
+indicating to all backup browsers and master browsers that
+we are a master browser.
+
+(note: if another master browser receives this announcement
+and thinks that it is also the master browser for this
+workgroup, it stops being a master browser and forces an
+election).
+
+if we are not a master browser, then we send an announcement
+notifying the master browser that we are a member of its
+workgroup.
+
+
+/*************************************************************************
+ remove_my_servers()
+ *************************************************************************/
+
+this function is responsible for informing other servers that
+samba is about to go down. it announces, on all subnets, that
+samba's time to live is zero and that it has no services.
+
+
+/*************************************************************************
+ do_announce_host()
+ *************************************************************************/
+
+this function is responsible for sending out an announcement
+MAILSLOT browse packet. it contains information such as the
+time to live, name of the server, services that the server
+offers etc.
+
+the format of this MAILSLOT browse packet is described in
+draft-heizer-cifs-v1-spec-00.txt 3.9.50.4.1 page 165-6.
+
+
+/*************************************************************************
+ announce_backup()
+ *************************************************************************/
+
+this function is responsible for getting master browsers and domain
+controllers to send us lists of backup servers. this is done by
+sending an ANN_GetBackupListReq browse mailslot.
+
+the master browser, or primary domain controller, should respond
+with an ANN_GetBackupListResp browse mailslot containing the list
+of backup servers.
+
+
+/*************************************************************************
+ sync_server()
+ *************************************************************************/
+
+this function is responsible for initiating a sync browse list
+sequence and, if necessary, carrying out an ANN_MasterAnnouncement
+to the primary domain controller (that we are also sync'ing
+browse lists with).
+
+see nameservresp.c:response_name_status_check().
+
+
+/*************************************************************************
+ announce_request()
+ *************************************************************************/
+
+this function is responsible for sending an announcement request to
+another server. this server should respond with an announcement.
+
+if the announce request is sent to WORKGROUP(0x1e) then members of
+the workgroup will respond (with ANN_HostAnnounce packets)
+
+if the announce request is sent to WORKGROUP(0x1d) then the master
+browser of the workgroup should respond (ANN_LocalMasterAnnounce).
+this is untested.
+
+if the announce request is sent to ^1^2__MSBROWSE__^2(0x1) then
+(and this is pure speculation), all backup browsers and master
+browsers should respond with ANN_DomainAnnounce packets.
+this is untested.
+
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/namebrowse.c samba-1.9.16alpha11/source/namebrowse.c
--- samba-1.9.16alpha10/source/namebrowse.c Thu Jan 1 10:00:00 1970
+++ samba-1.9.16alpha11/source/namebrowse.c Sun Jul 7 22:35:54 1996
@@ -0,0 +1,217 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1995
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Revision History:
+
+ 14 jan 96: lkcl@pires.co.uk
+ added multiple workgroup domain master support
+
+*/
+
+#include "includes.h"
+#include "smb.h"
+
+extern int ClientNMB;
+
+extern int DEBUGLEVEL;
+
+/* this is our browse master/backup cache database */
+static struct browse_cache_record *browserlist = NULL;
+
+
+/***************************************************************************
+ add a browser into the list
+ **************************************************************************/
+static void add_browse_cache(struct browse_cache_record *b)
+{
+ struct browse_cache_record *b2;
+
+ if (!browserlist)
+ {
+ browserlist = b;
+ b->prev = NULL;
+ b->next = NULL;
+ return;
+ }
+
+ for (b2 = browserlist; b2->next; b2 = b2->next) ;
+
+ b2->next = b;
+ b->next = NULL;
+ b->prev = b2;
+}
+
+
+/*******************************************************************
+ remove old browse entries
+ ******************************************************************/
+void expire_browse_cache(time_t t)
+{
+ struct browse_cache_record *b;
+ struct browse_cache_record *nextb;
+
+ /* expire old entries in the serverlist */
+ for (b = browserlist; b; b = nextb)
+ {
+ if (b->synced && b->sync_time < t)
+ {
+ DEBUG(3,("Removing dead cached browser %s\n",b->name));
+ nextb = b->next;
+
+ if (b->prev) b->prev->next = b->next;
+ if (b->next) b->next->prev = b->prev;
+
+ if (browserlist == b) browserlist = b->next;
+
+ free(b);
+ }
+ else
+ {
+ nextb = b->next;
+ }
+ }
+}
+
+
+/****************************************************************************
+ add a browser entry
+ ****************************************************************************/
+struct browse_cache_record *add_browser_entry(char *name, int type, char *wg,
+ time_t ttl, struct in_addr ip)
+{
+ BOOL newentry=False;
+
+ struct browse_cache_record *b;
+
+ /* search for the entry: if it's already in the cache, update that entry */
+ for (b = browserlist; b; b = b->next)
+ {
+ if (ip_equal(ip,b->ip) && strequal(b->group, wg)) break;
+ }
+
+ if (b && b->synced)
+ {
+ /* entries get left in the cache for a while. this stops sync'ing too
+ often if the network is large */
+ DEBUG(4, ("browser %s %s %s already sync'd at time %d\n",
+ b->name, b->group, inet_ntoa(b->ip), b->sync_time));
+ return NULL;
+ }
+
+ if (!b)
+ {
+ newentry = True;
+ b = (struct browse_cache_record *)malloc(sizeof(*b));
+
+ if (!b) return(NULL);
+
+ bzero((char *)b,sizeof(*b));
+ }
+
+ /* update the entry */
+ ttl = time(NULL)+ttl;
+
+ StrnCpy(b->name ,name,sizeof(b->name )-1);
+ StrnCpy(b->group,wg ,sizeof(b->group)-1);
+ strupper(b->name);
+ strupper(b->group);
+
+ b->ip = ip;
+ b->type = type;
+
+ if (newentry || ttl < b->sync_time)
+ b->sync_time = ttl;
+
+ if (newentry)
+ {
+ b->synced = False;
+ add_browse_cache(b);
+
+ DEBUG(3,("Added cache entry %s %s(%2x) %s ttl %d\n",
+ wg, name, type, inet_ntoa(ip),ttl));
+ }
+ else
+ {
+ DEBUG(3,("Updated cache entry %s %s(%2x) %s ttl %d\n",
+ wg, name, type, inet_ntoa(ip),ttl));
+ }
+
+ return(b);
+}
+
+
+/****************************************************************************
+find a server responsible for a workgroup, and sync browse lists
+**************************************************************************/
+static void start_sync_browse_entry(struct browse_cache_record *b)
+{
+ struct subnet_record *d;
+ struct work_record *work;
+
+ if (!(d = find_subnet(b->ip))) return;
+
+ if (!(work = find_workgroupstruct(d, b->group, False))) return;
+
+ /* only sync if we are the master */
+ if (AM_MASTER(work)) {
+
+ /* first check whether the group we intend to sync with exists. if it
+ doesn't, the server must have died. o dear. */
+
+ /* see response_netbios_packet() or expire_netbios_response_entries() */
+ queue_netbios_packet(d,ClientNMB,NMB_QUERY,NAME_QUERY_SYNC,
+ b->group,0x20,0,0,
+ False,False,b->ip,b->ip);
+ }
+
+ b->synced = True;
+}
+
+
+/****************************************************************************
+ search through browser list for an entry to sync with
+ **************************************************************************/
+void do_browser_lists(void)
+{
+ struct browse_cache_record *b;
+ static time_t last = 0;
+ time_t t = time(NULL);
+
+ if (t-last < 20) return; /* don't do too many of these at once! */
+ /* XXXX equally this period should not be too long
+ the server may die in the intervening gap */
+
+ last = t;
+
+ /* pick any entry in the list, preferably one whose time is up */
+ for (b = browserlist; b && b->next; b = b->next)
+ {
+ if (b->sync_time < t && b->synced == False) break;
+ }
+
+ if (b && !b->synced)
+ {
+ /* sync with the selected entry then remove some dead entries */
+ start_sync_browse_entry(b);
+ expire_browse_cache(t - 60);
+ }
+
+}
+
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/namebrowse.doc samba-1.9.16alpha11/source/namebrowse.doc
--- samba-1.9.16alpha10/source/namebrowse.doc Thu Jan 1 10:00:00 1970
+++ samba-1.9.16alpha11/source/namebrowse.doc Sun Jul 7 22:35:54 1996
@@ -0,0 +1,69 @@
+this module deals with queueing servers that samba must sync browse
+lists with. it will always issue a name query immediately before
+actually carrying out the NetServerEnum call, to ensure that time
+is not wasted by a remote server's failure.
+
+this module was created to minimise the amount of NetServerEnum calls
+that samba may be asked to perform, by maintaining the name of a server
+for up to a minute after the NetServerEnum call was issued, and
+disallowing further NetServerEnum calls to this remote server until
+the entry is removed.
+
+samba can ask for a NetServerEnum call to be issued to grab a remote
+server's list of servers and workgroups either in its capacity as
+a primary domain controller (domain master browser), as a local
+master browser.
+
+samba does not deal with becoming a backup master browser properly
+at present.
+
+
+/*************************************************************************
+ do_browser_lists()
+ *************************************************************************/
+
+this function is responsible for finding an appropriate entry in the
+sync browser cache, initiating a name query (which results in a
+NetServerEnum call if there is a positive response), and then
+removing all entries that have been actioned and have been around
+for over a minute.
+
+
+/*************************************************************************
+ start_sync_browse_entry()
+ *************************************************************************/
+
+this function is responsible for initiating a name query. if a
+positive response is received, then this will result in a
+NetServerEnum api call.
+
+samba will only initiate this process if it is a master browser
+for this workgroup.
+
+
+/*************************************************************************
+ add_browser_entry()
+ *************************************************************************/
+
+this function is responsible for adding a browser into the list of
+servers to sync browse lists with. if the server entry has already
+been added and syncing browse lists has already been initiated, it
+will not be added again.
+
+
+/*************************************************************************
+ expire_browse_cache()
+ *************************************************************************/
+
+this function is responsible for removing entries that have had the
+sync browse list initiated (whether that succeeded or not is beyond
+this function's scope) and have been in the cache for a while.
+
+
+/*************************************************************************
+ add_browse_entry()
+ *************************************************************************/
+
+this function is responsible for adding a new entry into the list
+of servers to sync browse lists with at some point in the near future.
+
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/namedb.c samba-1.9.16alpha11/source/namedb.c
--- samba-1.9.16alpha10/source/namedb.c Mon Jun 10 15:18:56 1996
+++ samba-1.9.16alpha11/source/namedb.c Thu Jan 1 10:00:00 1970
@@ -1,720 +0,0 @@
-/*
- Unix SMB/Netbios implementation.
- Version 1.9.
- NBT netbios routines and daemon - version 2
- Copyright (C) Andrew Tridgell 1994-1995
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
- Revision History:
-
- 14 jan 96: lkcl@pires.co.uk
- added multiple workgroup domain master support
-
-*/
-
-#include "includes.h"
-#include "smb.h"
-
-extern int ClientNMB;
-extern int ClientDGRAM;
-
-extern int DEBUGLEVEL;
-
-extern time_t StartupTime;
-extern pstring myname;
-extern pstring scope;
-
-extern struct in_addr ipgrp;
-
-/* this is our browse master/backup cache database */
-struct browse_cache_record *browserlist = NULL;
-
-/* this is our domain/workgroup/server database */
-struct subnet_record *subnetlist = NULL;
-
-static BOOL updatedlists = True;
-int updatecount=0;
-
-int workgroup_count = 0; /* unique index key: one for each workgroup */
-
-/* what server type are we currently */
-
-#define DFLT_SERVER_TYPE (SV_TYPE_WORKSTATION | SV_TYPE_SERVER | \
- SV_TYPE_TIME_SOURCE | SV_TYPE_SERVER_UNIX | \
- SV_TYPE_PRINTQ_SERVER | SV_TYPE_POTENTIAL_BROWSER)
-
-
-/****************************************************************************
- add a workgroup into the domain list
- **************************************************************************/
-static void add_workgroup(struct work_record *work, struct subnet_record *d)
-{
- struct work_record *w2;
-
- if (!work || !d) return;
-
- if (!d->workgrouplist)
- {
- d->workgrouplist = work;
- work->prev = NULL;
- work->next = NULL;
- return;
- }
-
- for (w2 = d->workgrouplist; w2->next; w2 = w2->next);
-
- w2->next = work;
- work->next = NULL;
- work->prev = w2;
-}
-
-
-/****************************************************************************
- create a blank workgroup
- **************************************************************************/
-static struct work_record *make_workgroup(char *name)
-{
- struct work_record *work;
- struct subnet_record *d;
- int t = -1;
-
- if (!name || !name[0]) return NULL;
-
- work = (struct work_record *)malloc(sizeof(*work));
- if (!work) return(NULL);
-
- StrnCpy(work->work_group,name,sizeof(work->work_group)-1);
- work->serverlist = NULL;
-
- work->ServerType = DFLT_SERVER_TYPE;
- work->RunningElection = False;
- work->ElectionCount = 0;
- work->needelection = False;
- work->needannounce = True;
-
- /* make sure all token representations of workgroups are unique */
-
- for (d = subnetlist; d && t == -1; d = d->next)
- {
- struct work_record *w;
- for (w = d->workgrouplist; w && t == -1; w = w->next)
- {
- if (strequal(w->work_group, work->work_group)) t = w->token;
- }
- }
-
- if (t == -1)
- {
- work->token = ++workgroup_count;
- }
- else
- {
- work->token = t;
- }
-
-
- /* WfWg uses 01040b01 */
- /* Win95 uses 01041501 */
- /* NTAS uses ???????? */
- work->ElectionCriterion = (MAINTAIN_LIST<<1)|(ELECTION_VERSION<<8);
- work->ElectionCriterion |= (lp_os_level() << 24);
- if (lp_domain_master()) {
- work->ElectionCriterion |= 0x80;
- }
-
- return work;
-}
-
-
-/*******************************************************************
- expire old servers in the serverlist
- time of -1 indicates everybody dies
- ******************************************************************/
-static void remove_old_servers(struct work_record *work, time_t t)
-{
- struct server_record *s;
- struct server_record *nexts;
-
- /* expire old entries in the serverlist */
- for (s = work->serverlist; s; s = nexts)
- {
- if (t == -1 || (s->death_time && s->death_time < t))
- {
- DEBUG(3,("Removing dead server %s\n",s->serv.name));
- updatedlists = True;
- nexts = s->next;
-
- if (s->prev) s->prev->next = s->next;
- if (s->next) s->next->prev = s->prev;
-
- if (work->serverlist == s)
- work->serverlist = s->next;
-
- free(s);
- }
- else
- {
- nexts = s->next;
- }
- }
-}
-
-
-/*******************************************************************
- remove workgroups
- ******************************************************************/
-struct work_record *remove_workgroup(struct subnet_record *d,
- struct work_record *work)
-{
- struct work_record *ret_work = NULL;
-
- if (!d || !work) return NULL;
-
- DEBUG(3,("Removing old workgroup %s\n", work->work_group));
-
- remove_old_servers(work, -1);
-
- ret_work = work->next;
-
- if (work->prev) work->prev->next = work->next;
- if (work->next) work->next->prev = work->prev;
-
- if (d->workgrouplist == work) d->workgrouplist = work->next;
-
- free(work);
-
- return ret_work;
-}
-
-
-/****************************************************************************
- add a domain into the list
- **************************************************************************/
-static void add_subnet(struct subnet_record *d)
-{
- struct subnet_record *d2;
-
- if (!subnetlist)
- {
- subnetlist = d;
- d->prev = NULL;
- d->next = NULL;
- return;
- }
-
- for (d2 = subnetlist; d2->next; d2 = d2->next);
-
- d2->next = d;
- d->next = NULL;
- d->prev = d2;
-}
-
-/***************************************************************************
- add a browser into the list
- **************************************************************************/
-static void add_browse_cache(struct browse_cache_record *b)
-{
- struct browse_cache_record *b2;
-
- if (!browserlist)
- {
- browserlist = b;
- b->prev = NULL;
- b->next = NULL;
- return;
- }
-
- for (b2 = browserlist; b2->next; b2 = b2->next) ;
-
- b2->next = b;
- b->next = NULL;
- b->prev = b2;
-}
-
-
-/***************************************************************************
- add a server into the list
- **************************************************************************/
-static void add_server(struct work_record *work,struct server_record *s)
-{
- struct server_record *s2;
-
- if (!work->serverlist) {
- work->serverlist = s;
- s->prev = NULL;
- s->next = NULL;
- return;
- }
-
- for (s2 = work->serverlist; s2->next; s2 = s2->next) ;
-
- s2->next = s;
- s->next = NULL;
- s->prev = s2;
-}
-
-
-/*******************************************************************
- remove old browse entries
- ******************************************************************/
-void expire_browse_cache(time_t t)
-{
- struct browse_cache_record *b;
- struct browse_cache_record *nextb;
-
- /* expire old entries in the serverlist */
- for (b = browserlist; b; b = nextb)
- {
- if (b->synced && b->sync_time < t)
- {
- DEBUG(3,("Removing dead cached browser %s\n",b->name));
- nextb = b->next;
-
- if (b->prev) b->prev->next = b->next;
- if (b->next) b->next->prev = b->prev;
-
- if (browserlist == b) browserlist = b->next;
-
- free(b);
- }
- else
- {
- nextb = b->next;
- }
- }
-}
-
-
-/****************************************************************************
- find a workgroup in the workgrouplist
- only create it if the domain allows it, or the parameter 'add' insists
- that it get created/added anyway. this allows us to force entries in
- lmhosts file to be added.
- **************************************************************************/
-struct work_record *find_workgroupstruct(struct subnet_record *d,
- fstring name, BOOL add)
-{
- struct work_record *ret, *work;
-
- if (!d) return NULL;
-
- DEBUG(4, ("workgroup search for %s: ", name));
-
- if (strequal(name, "*"))
- {
- DEBUG(2,("add any workgroups: initiating browser search on %s\n",
- inet_ntoa(d->bcast_ip)));
- queue_netbios_pkt_wins(ClientNMB,NMB_QUERY, FIND_MASTER,
- MSBROWSE,0x1,0,
- True,False, d->bcast_ip);
- return NULL;
- }
-
- for (ret = d->workgrouplist; ret; ret = ret->next) {
- if (!strcmp(ret->work_group,name)) {
- DEBUG(4, ("found\n"));
- return(ret);
- }
- }
-
- if (!add) {
- DEBUG(4, ("not found\n"));
- return NULL;
- }
-
- DEBUG(4,("not found: creating\n"));
-
- if ((work = make_workgroup(name)))
- {
- if (lp_preferred_master() &&
- strequal(lp_workgroup(), name) &&
- d->my_interface)
- {
- DEBUG(3, ("preferred master startup for %s\n", work->work_group));
- work->needelection = True;
- work->ElectionCriterion |= (1<<3);
- }
- if (!d->my_interface)
- {
- work->needelection = False;
- }
- add_workgroup(work, d);
- return(work);
- }
- return NULL;
-}
-
-/****************************************************************************
- find a domain in the subnetlist
- **************************************************************************/
-struct subnet_record *find_domain(struct in_addr ip)
-{
- struct subnet_record *d;
-
- /* search through domain list for broadcast/netmask that matches
- the source ip address */
-
- for (d = subnetlist; d; d = d->next)
- {
- if (same_net(ip, d->bcast_ip, d->mask_ip))
- return(d);
- }
-
- return (NULL);
-}
-
-
-/****************************************************************************
- dump a copy of the workgroup/domain database
- **************************************************************************/
-void dump_workgroups(void)
-{
- struct subnet_record *d;
-
- for (d = subnetlist; d; d = d->next)
- {
- if (d->workgrouplist)
- {
- struct work_record *work;
-
- DEBUG(4,("dump domain bcast=%15s: ", inet_ntoa(d->bcast_ip)));
- DEBUG(4,(" netmask=%15s:\n", inet_ntoa(d->mask_ip)));
-
- for (work = d->workgrouplist; work; work = work->next)
- {
- DEBUG(4,("\t%s(%d)\n", work->work_group, work->token));
- if (work->serverlist)
- {
- struct server_record *s;
- for (s = work->serverlist; s; s = s->next)
- {
- DEBUG(4,("\t\t%s %8x (%s)\n",
- s->serv.name, s->serv.type, s->serv.comment));
- }
- }
- }
- }
- }
-}
-
-/****************************************************************************
- create a domain entry
- ****************************************************************************/
-static struct subnet_record *make_subnet(struct in_addr bcast_ip,
- struct in_addr mask)
-{
- struct subnet_record *d;
- d = (struct subnet_record *)malloc(sizeof(*d));
-
- if (!d) return(NULL);
-
- bzero((char *)d,sizeof(*d));
-
- DEBUG(4,("making subnet %s ", inet_ntoa(bcast_ip)));
- DEBUG(4,("%s\n", inet_ntoa(mask)));
-
- d->bcast_ip = bcast_ip;
- d->mask_ip = mask;
- d->workgrouplist = NULL;
- d->my_interface = ismybcast(d->bcast_ip);
-
- add_subnet(d);
-
- return d;
-}
-
-/****************************************************************************
- add a domain entry. creates a workgroup, if necessary, and adds the domain
- to the named a workgroup.
- ****************************************************************************/
-struct subnet_record *add_subnet_entry(struct in_addr source_ip,
- struct in_addr source_mask,
- char *name, BOOL add)
-{
- struct subnet_record *d;
- struct in_addr ip;
-
- ip = ipgrp;
-
- if (zero_ip(source_ip))
- source_ip = *iface_bcast(source_ip);
-
- /* add the domain into our domain database */
- if ((d = find_domain(source_ip)) ||
- (d = make_subnet(source_ip, source_mask)))
- {
- struct work_record *w = find_workgroupstruct(d, name, add);
-
- if (!w) return NULL;
-
- /* add WORKGROUP(1e) and WORKGROUP(00) entries into name database
- or register with WINS server, if it's our workgroup */
- if (strequal(lp_workgroup(), name))
- {
- extern pstring ServerComment;
- add_name_entry(name,0x1e,NB_ACTIVE|NB_GROUP);
- add_name_entry(name,0x0 ,NB_ACTIVE|NB_GROUP);
- add_server_entry(d,w,myname,w->ServerType,0,ServerComment,True);
- }
-
- DEBUG(3,("Added domain name entry %s at %s\n", name,inet_ntoa(ip)));
- return d;
- }
- return NULL;
-}
-
-/****************************************************************************
- add a browser entry
- ****************************************************************************/
-struct browse_cache_record *add_browser_entry(char *name, int type, char *wg,
- time_t ttl, struct in_addr ip)
-{
- BOOL newentry=False;
-
- struct browse_cache_record *b;
-
- /* search for the entry: if it's already in the cache, update that entry */
- for (b = browserlist; b; b = b->next)
- {
- if (ip_equal(ip,b->ip) && strequal(b->group, wg)) break;
- }
-
- if (b && b->synced)
- {
- /* entries get left in the cache for a while. this stops sync'ing too
- often if the network is large */
- DEBUG(4, ("browser %s %s %s already sync'd at time %d\n",
- b->name, b->group, inet_ntoa(b->ip), b->sync_time));
- return NULL;
- }
-
- if (!b)
- {
- newentry = True;
- b = (struct browse_cache_record *)malloc(sizeof(*b));
-
- if (!b) return(NULL);
-
- bzero((char *)b,sizeof(*b));
- }
-
- /* update the entry */
- ttl = time(NULL)+ttl;
-
- StrnCpy(b->name ,name,sizeof(b->name )-1);
- StrnCpy(b->group,wg ,sizeof(b->group)-1);
- strupper(b->name);
- strupper(b->group);
-
- b->ip = ip;
- b->type = type;
-
- if (newentry || ttl < b->sync_time)
- b->sync_time = ttl;
-
- if (newentry)
- {
- b->synced = False;
- add_browse_cache(b);
-
- DEBUG(3,("Added cache entry %s %s(%2x) %s ttl %d\n",
- wg, name, type, inet_ntoa(ip),ttl));
- }
- else
- {
- DEBUG(3,("Updated cache entry %s %s(%2x) %s ttl %d\n",
- wg, name, type, inet_ntoa(ip),ttl));
- }
-
- return(b);
-}
-
-
-/****************************************************************************
- add a server entry
- ****************************************************************************/
-struct server_record *add_server_entry(struct subnet_record *d,
- struct work_record *work,
- char *name,int servertype,
- int ttl,char *comment,
- BOOL replace)
-{
- BOOL newentry=False;
- struct server_record *s;
-
- if (name[0] == '*')
- {
- return (NULL);
- }
-
- for (s = work->serverlist; s; s = s->next)
- {
- if (strequal(name,s->serv.name)) break;
- }
-
- if (s && !replace)
- {
- DEBUG(4,("Not replacing %s\n",name));
- return(s);
- }
-
- updatedlists=True;
-
- if (!s)
- {
- newentry = True;
- s = (struct server_record *)malloc(sizeof(*s));
-
- if (!s) return(NULL);
-
- bzero((char *)s,sizeof(*s));
- }
-
- if (d->my_interface &&
- strequal(lp_workgroup(),work->work_group))
- {
- if (servertype)
- servertype |= SV_TYPE_LOCAL_LIST_ONLY;
- }
- else
- {
- servertype &= ~SV_TYPE_LOCAL_LIST_ONLY;
- }
-
- /* update the entry */
- StrnCpy(s->serv.name,name,sizeof(s->serv.name)-1);
- StrnCpy(s->serv.comment,comment,sizeof(s->serv.comment)-1);
- strupper(s->serv.name);
- s->serv.type = servertype;
- s->death_time = ttl?time(NULL)+ttl*3:0;
-
- if (servertype == 0)
- s->death_time = time(NULL)-1;
-
- /* for a domain entry, the comment field refers to the server name */
-
- if (s->serv.type & SV_TYPE_DOMAIN_ENUM) strupper(s->serv.comment);
-
- if (newentry)
- {
- add_server(work, s);
-
- DEBUG(3,("Added "));
- }
- else
- {
- DEBUG(3,("Updated "));
- }
-
- DEBUG(3,("server entry %s of type %x (%s) to %s %s\n",
- name,servertype,comment,
- work->work_group,inet_ntoa(d->bcast_ip)));
-
- return(s);
-}
-
-
-/*******************************************************************
- write out browse.dat
- ******************************************************************/
-void write_browse_list(void)
-{
- struct subnet_record *d;
-
- pstring fname,fnamenew;
- FILE *f;
-
- if (!updatedlists) return;
-
- dump_names();
- dump_workgroups();
-
- updatedlists = False;
- updatecount++;
-
- strcpy(fname,lp_lockdir());
- trim_string(fname,NULL,"/");
- strcat(fname,"/");
- strcat(fname,SERVER_LIST);
- strcpy(fnamenew,fname);
- strcat(fnamenew,".");
-
- f = fopen(fnamenew,"w");
-
- if (!f)
- {
- DEBUG(4,("Can't open %s - %s\n",fnamenew,strerror(errno)));
- return;
- }
-
- for (d = subnetlist; d ; d = d->next)
- {
- struct work_record *work;
- for (work = d->workgrouplist; work ; work = work->next)
- {
- struct server_record *s;
- for (s = work->serverlist; s ; s = s->next)
- {
- fstring tmp;
-
- /* don't list domains I don't have a master for */
- if ((s->serv.type & SV_TYPE_DOMAIN_ENUM) &&
- !s->serv.comment[0])
- {
- continue;
- }
-
- /* output server details, plus what workgroup/domain
- they're in. without the domain information, the
- combined list of all servers in all workgroups gets
- sent to anyone asking about any workgroup! */
-
- sprintf(tmp, "\"%s\"", s->serv.name);
- fprintf(f, "%-25s ", tmp);
- fprintf(f, "%08x ", s->serv.type);
- sprintf(tmp, "\"%s\" ", s->serv.comment);
- fprintf(f, "%-30s", tmp);
- fprintf(f, "\"%s\"\n", work->work_group);
- }
- }
- }
-
- fclose(f);
- unlink(fname);
- chmod(fnamenew,0644);
- rename(fnamenew,fname);
- DEBUG(3,("Wrote browse list %s\n",fname));
-}
-
-
-/*******************************************************************
- expire old servers in the serverlist
- ******************************************************************/
-void expire_servers(time_t t)
-{
- struct subnet_record *d;
-
- for (d = subnetlist ; d ; d = d->next)
- {
- struct work_record *work;
-
- for (work = d->workgrouplist; work; work = work->next)
- {
- remove_old_servers(work, t);
- }
- }
-}
-
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/namedbname.c samba-1.9.16alpha11/source/namedbname.c
--- samba-1.9.16alpha10/source/namedbname.c Thu Jan 1 10:00:00 1970
+++ samba-1.9.16alpha11/source/namedbname.c Thu Jul 18 20:53:15 1996
@@ -0,0 +1,548 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1996
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Module name: namedbname.c
+
+ Revision History:
+
+ 14 jan 96: lkcl@pires.co.uk
+ added multiple workgroup domain master support
+
+ 04 jul 96: lkcl@pires.co.uk
+ created module namedbname containing name database functions
+*/
+
+#include "includes.h"
+
+extern int DEBUGLEVEL;
+
+extern pstring scope;
+extern struct in_addr ipzero;
+extern struct in_addr ipgrp;
+
+extern struct subnet_record *subnetlist;
+
+#define WINS_LIST "wins.dat"
+
+
+/****************************************************************************
+ true if two netbios names are equal
+****************************************************************************/
+BOOL name_equal(struct nmb_name *n1,struct nmb_name *n2)
+{
+ return n1->name_type == n2->name_type &&
+ strequal(n1->name ,n2->name ) &&
+ strequal(n1->scope,n2->scope);
+}
+
+
+/****************************************************************************
+ true if the netbios name is ^1^2__MSBROWSE__^2^1
+
+ note: this name is registered if as a master browser or backup browser
+ you are responsible for a workgroup (when you announce a domain by
+ broadcasting on your local subnet, you announce it as coming from this
+ name: see announce_host()).
+
+ **************************************************************************/
+BOOL ms_browser_name(char *name, int type)
+{
+ return strequal(name,MSBROWSE) && type == 0x01;
+}
+
+
+/****************************************************************************
+ add a netbios name into the namelist
+ **************************************************************************/
+static void add_name(struct subnet_record *d, struct name_record *n)
+{
+ struct name_record *n2;
+
+ if (!d) return;
+
+ if (!d->namelist)
+ {
+ d->namelist = n;
+ n->prev = NULL;
+ n->next = NULL;
+ return;
+ }
+
+ for (n2 = d->namelist; n2->next; n2 = n2->next) ;
+
+ n2->next = n;
+ n->next = NULL;
+ n->prev = n2;
+}
+
+
+/****************************************************************************
+ remove a name from the namelist. The pointer must be an element just
+ retrieved
+ **************************************************************************/
+void remove_name(struct subnet_record *d, struct name_record *n)
+{
+ struct name_record *nlist;
+ if (!d) return;
+
+ nlist = d->namelist;
+
+ while (nlist && nlist != n) nlist = nlist->next;
+
+ if (nlist)
+ {
+ if (nlist->next) nlist->next->prev = nlist->prev;
+ if (nlist->prev) nlist->prev->next = nlist->next;
+ free(nlist);
+ }
+}
+
+
+/****************************************************************************
+ find a name in a namelist.
+ **************************************************************************/
+struct name_record *find_name(struct name_record *n,
+ struct nmb_name *name,
+ int search)
+{
+ struct name_record *ret;
+
+ for (ret = n; ret; ret = ret->next)
+ {
+ if (name_equal(&ret->name,name))
+ {
+ /* self search: self names only */
+ if ((search&FIND_SELF) == FIND_SELF && ret->source != SELF)
+ continue;
+
+ return ret;
+ }
+ }
+ return NULL;
+}
+
+
+/****************************************************************************
+ find a name in the domain database namelist
+ search can be any of:
+ FIND_SELF - look exclusively for names the samba server has added for itself
+ FIND_LOCAL - look for names in the local subnet record.
+ FIND_WINS - look for names in the WINS record
+ **************************************************************************/
+struct name_record *find_name_search(struct subnet_record **d,
+ struct nmb_name *name,
+ int search, struct in_addr ip)
+{
+ if (d == NULL) return NULL; /* bad error! */
+
+ if ((search & FIND_LOCAL) == FIND_LOCAL)
+ {
+ if (*d != NULL)
+ {
+ DEBUG(4,("find_name on local: %s %s search %x\n",
+ namestr(name),inet_ntoa(ip), search));
+ return find_name((*d)->namelist, name, search);
+ }
+ else
+ {
+ DEBUG(4,("local find_name_search with a NULL subnet pointer\n"));
+ return NULL;
+ }
+ }
+
+ if ((search & FIND_WINS) != FIND_WINS) return NULL;
+
+ if (*d == NULL)
+ {
+ /* find WINS subnet record */
+ *d = find_subnet(ipgrp);
+ }
+
+ if (*d == NULL) return NULL;
+
+ DEBUG(4,("find_name on WINS: %s %s search %x\n",
+ namestr(name),inet_ntoa(ip), search));
+ return find_name((*d)->namelist, name, search);
+}
+
+
+/****************************************************************************
+ dump a copy of the name table
+ **************************************************************************/
+void dump_names(void)
+{
+ struct name_record *n;
+ struct subnet_record *d;
+ fstring fname, fnamenew;
+ time_t t = time(NULL);
+
+ FILE *f;
+
+ strcpy(fname,lp_lockdir());
+ trim_string(fname,NULL,"/");
+ strcat(fname,"/");
+ strcat(fname,WINS_LIST);
+ strcpy(fnamenew,fname);
+ strcat(fnamenew,".");
+
+ f = fopen(fnamenew,"w");
+
+ if (!f)
+ {
+ DEBUG(4,("Can't open %s - %s\n",fnamenew,strerror(errno)));
+ }
+
+ DEBUG(3,("Dump of local name table:\n"));
+
+ for (d = subnetlist; d; d = d->next)
+ for (n = d->namelist; n; n = n->next)
+ {
+ if (f && ip_equal(d->bcast_ip, ipgrp) && n->source == REGISTER)
+ {
+ fstring data;
+
+ /* XXXX i have little imagination as to how to output nb_flags as
+ anything other than as a hexadecimal number :-) */
+
+ sprintf(data, "%s#%02x %s %2x %ld",
+ n->name.name,n->name.name_type, /* XXXX ignore the scope for now */
+ inet_ntoa(n->ip),
+ n->nb_flags,
+ n->death_time);
+ fprintf(f, "%s\n", data);
+ }
+
+ DEBUG(3,("%15s ", inet_ntoa(d->bcast_ip)));
+ DEBUG(3,("%15s ", inet_ntoa(d->mask_ip)));
+ DEBUG(3,("%-19s %15s NB=%2x TTL=%ld \n",
+ namestr(&n->name),
+ inet_ntoa(n->ip),
+ n->nb_flags,
+ n->death_time?n->death_time-t:0));
+ }
+
+ fclose(f);
+ unlink(fname);
+ chmod(fnamenew,0644);
+ rename(fnamenew,fname);
+
+ DEBUG(3,("Wrote wins database %s\n",fname));
+}
+
+
+/****************************************************************************
+load a netbios name database file
+****************************************************************************/
+void load_netbios_names(void)
+{
+ struct subnet_record *d = find_subnet(ipgrp);
+ fstring fname;
+
+ FILE *f;
+ pstring line;
+
+ if (!d) return;
+
+ strcpy(fname,lp_lockdir());
+ trim_string(fname,NULL,"/");
+ strcat(fname,"/");
+ strcat(fname,WINS_LIST);
+
+ f = fopen(fname,"r");
+
+ if (!f) {
+ DEBUG(2,("Can't open wins database file %s\n",fname));
+ return;
+ }
+
+ while (!feof(f))
+ {
+ pstring name_str, ip_str, ttd_str, nb_flags_str;
+
+ pstring name;
+ int type = 0;
+ int nb_flags;
+ time_t ttd;
+ struct in_addr ipaddr;
+
+ enum name_source source;
+
+ char *ptr;
+ int count = 0;
+
+ char *p;
+
+ if (!fgets_slash(line,sizeof(pstring),f)) continue;
+
+ if (*line == '#') continue;
+
+ ptr = line;
+
+ if (next_token(&ptr,name_str ,NULL)) ++count;
+ if (next_token(&ptr,ip_str ,NULL)) ++count;
+ if (next_token(&ptr,ttd_str ,NULL)) ++count;
+ if (next_token(&ptr,nb_flags_str,NULL)) ++count;
+
+ if (count <= 0) continue;
+
+ if (count != 4) {
+ DEBUG(0,("Ill formed wins line"));
+ DEBUG(0,("[%s]: name#type ip nb_flags abs_time\n",line));
+ continue;
+ }
+
+ /* netbios name. # divides the name from the type (hex): netbios#xx */
+ strcpy(name,name_str);
+
+ p = strchr(name,'#');
+
+ if (p) {
+ *p = 0;
+ sscanf(p+1,"%x",&type);
+ }
+
+ /* decode the netbios flags (hex) and the time-to-die (seconds) */
+ sscanf(nb_flags_str,"%x",&nb_flags);
+ sscanf(ttd_str,"%ld",&ttd);
+
+ ipaddr = *interpret_addr2(ip_str);
+
+ if (ip_equal(ipaddr,ipzero)) {
+ source = SELF;
+ }
+ else
+ {
+ source = REGISTER;
+ }
+
+ DEBUG(4, ("add WINS line: %s#%02x %s %ld %2x\n",
+ name,type, inet_ntoa(ipaddr), ttd, nb_flags));
+
+ /* add all entries that have 60 seconds or more to live */
+ if (ttd - 60 < time(NULL) || ttd == 0)
+ {
+ time_t t = (ttd?ttd-time(NULL):0) / 3;
+
+ /* add netbios entry read from the wins.dat file. IF it's ok */
+ add_netbios_entry(d,name,type,nb_flags,t,source,ipaddr,True,True);
+ }
+ }
+
+ fclose(f);
+}
+
+
+/****************************************************************************
+ remove an entry from the name list
+ ****************************************************************************/
+void remove_netbios_name(struct subnet_record *d,
+ char *name,int type, enum name_source source,
+ struct in_addr ip)
+{
+ struct nmb_name nn;
+ struct name_record *n;
+
+ make_nmb_name(&nn, name, type, scope);
+ n = find_name_search(&d, &nn, FIND_LOCAL, ip);
+
+ if (n && n->source == source) remove_name(d,n);
+}
+
+
+/****************************************************************************
+ add an entry to the name list.
+
+ this is a multi-purpose function.
+
+ it adds samba's own names in to its records on each interface, keeping a
+ record of whether it is a master browser, domain master, or WINS server.
+
+ it also keeps a record of WINS entries.
+
+ ****************************************************************************/
+struct name_record *add_netbios_entry(struct subnet_record *d,
+ char *name, int type, int nb_flags,
+ int ttl, enum name_source source, struct in_addr ip,
+ BOOL new_only,BOOL wins)
+{
+ struct name_record *n;
+ struct name_record *n2=NULL;
+ int search = 0;
+ BOOL self = source == SELF;
+
+ /* add the name to the WINS list if the name comes from a directed query */
+ search |= wins ? FIND_WINS : FIND_LOCAL;
+ /* search for SELF names only */
+ search |= self ? FIND_SELF : 0;
+
+ if (!self)
+ {
+ if (!wins && type != 0x1b)
+ {
+ /* the only broadcast (non-WINS) names we are adding are ours
+ (SELF) and PDC type names */
+ return NULL;
+ }
+ }
+
+ n = (struct name_record *)malloc(sizeof(*n));
+ if (!n) return(NULL);
+
+ bzero((char *)n,sizeof(*n));
+
+ make_nmb_name(&n->name,name,type,scope);
+
+ if ((n2 = find_name_search(&d, &n->name, search, new_only?ipzero:ip)))
+ {
+ free(n);
+ if (new_only || (n2->source==SELF && source!=SELF)) return n2;
+ n = n2;
+ }
+
+ if (ttl)
+ n->death_time = time(NULL)+ttl*3;
+ n->refresh_time = time(NULL)+GET_TTL(ttl);
+
+ n->ip = ip;
+ n->nb_flags = nb_flags;
+ n->source = source;
+
+ if (!n2) add_name(d,n);
+
+ DEBUG(3,("Added netbios name %s at %s ttl=%d nb_flags=%2x\n",
+ namestr(&n->name),inet_ntoa(ip),ttl,nb_flags));
+
+ return(n);
+}
+
+
+/*******************************************************************
+ expires old names in the namelist
+ ******************************************************************/
+void expire_names(time_t t)
+{
+ struct name_record *n;
+ struct name_record *next;
+ struct subnet_record *d;
+
+ /* expire old names */
+ for (d = subnetlist; d; d = d->next)
+ {
+ for (n = d->namelist; n; n = next)
+ {
+ if (n->death_time && n->death_time < t)
+ {
+ DEBUG(3,("Removing dead name %s\n", namestr(&n->name)));
+
+ next = n->next;
+
+ if (n->prev) n->prev->next = n->next;
+ if (n->next) n->next->prev = n->prev;
+
+ if (d->namelist == n) d->namelist = n->next;
+
+ free(n);
+ }
+ else
+ {
+ next = n->next;
+ }
+ }
+ }
+}
+
+
+/***************************************************************************
+ reply to a name query
+ ****************************************************************************/
+struct name_record *search_for_name(struct subnet_record **d,
+ struct nmb_name *question,
+ struct in_addr ip, int Time, int search)
+{
+ int name_type = question->name_type;
+ char *qname = question->name;
+ BOOL dns_type = name_type == 0x20 || name_type == 0;
+
+ struct name_record *n;
+
+ DEBUG(3,("Search for %s from %s - ", namestr(question), inet_ntoa(ip)));
+
+ /* first look up name in cache */
+ n = find_name_search(d,question,search,ip);
+
+ if (*d == NULL) return NULL;
+
+ DEBUG(4,("subnet %s ", inet_ntoa((*d)->bcast_ip)));
+
+ /* now try DNS lookup. */
+ if (!n)
+ {
+ struct in_addr dns_ip;
+ unsigned long a;
+
+ /* only do DNS lookups if the query is for type 0x20 or type 0x0 */
+ if (!dns_type && name_type != 0x1b)
+ {
+ DEBUG(3,("types 0x20 0x1b 0x0 only: name not found\n"));
+ return NULL;
+ }
+
+ /* look it up with DNS */
+ a = interpret_addr(qname);
+
+ putip((char *)&dns_ip,(char *)&a);
+
+ if (!a)
+ {
+ /* no luck with DNS. We could possibly recurse here XXXX */
+ DEBUG(3,("no recursion.\n"));
+ /* add the fail to our WINS cache of names. give it 1 hour in the cache */
+ add_netbios_entry(*d,qname,name_type,NB_ACTIVE,60*60,DNSFAIL,dns_ip,
+ True, True);
+ return NULL;
+ }
+
+ /* add it to our WINS cache of names. give it 2 hours in the cache */
+ n = add_netbios_entry(*d,qname,name_type,NB_ACTIVE,2*60*60,DNS,dns_ip,
+ True,True);
+
+ /* failed to add it? yikes! */
+ if (!n) return NULL;
+ }
+
+ /* is our entry already dead? */
+ if (n->death_time)
+ {
+ if (n->death_time < Time) return False;
+ }
+
+ /* it may have been an earlier failure */
+ if (n->source == DNSFAIL)
+ {
+ DEBUG(3,("DNSFAIL\n"));
+ return NULL;
+ }
+
+ DEBUG(3,("OK %s\n",inet_ntoa(n->ip)));
+
+ return n;
+}
+
+
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/namedbname.doc samba-1.9.16alpha11/source/namedbname.doc
--- samba-1.9.16alpha10/source/namedbname.doc Thu Jan 1 10:00:00 1970
+++ samba-1.9.16alpha11/source/namedbname.doc Sun Jul 7 22:35:55 1996
@@ -0,0 +1,155 @@
+this module deals with the NetBIOS name database for samba. it deals
+directly with adding, removing, finding, loading and saving of names.
+
+/*************************************************************************
+ search_for_name()
+ *************************************************************************/
+
+this function is responsible for finding a name in the appropriate part
+of samba's NetBIOS name database. if the name cannot be found, then it
+should look the name up using DNS. later modifications will be to
+forward the request on to another WINS server, should samba not be able
+to find out about the requested name (this will be implemented through
+issuing a new type of samba 'state').
+
+the name is first searched for in the NetBIOS cache. if it cannot be
+found, then it if the name looks like it's a server-type name (0x20
+0x0 or 0x1b) then DNS is used to look for the name.
+
+if DNS fails, then a record of this failure is kept. if it succeeds, then
+a new NetBIOS entry is added.
+
+the successfully found name is returned. on failure, NULL is returned.
+
+
+/*************************************************************************
+ expire_names()
+ *************************************************************************/
+
+this function is responsible for removing old NetBIOS names from its
+database. no further action is required.
+
+for over-zealous WINS systems, the use of query_refresh_names() is
+recommended. this function initiates polling of hosts that have
+registered with samba in its capacity as a WINS server. an alternative
+means to achieve the same end as query_refresh_names() is to
+reduce the time to live when the name is registered with samba,
+except that in this instance the responsibility for refreshing the
+name is with the owner of the name, not the server with which the name
+is registered.
+
+
+/*************************************************************************
+ add_netbios_entry()
+ *************************************************************************/
+
+this function is responsible for adding or updating a NetBIOS name
+in the database. into the local interface records, the only names
+that will be added are those of primary domain controllers and
+samba's own names. into the WINS records, all names are added.
+
+the name to be added / updated will be looked up in the records.
+if it is found, then we will not overwrite the entry if the flag
+'newonly' is True, or if the name is being added as a non-SELF
+(non-samba) name and the records indicate that samba owns the
+name.
+
+otherwise, the name is added or updated with the new details.
+
+
+/*************************************************************************
+ remove_netbios_entry()
+ *************************************************************************/
+
+this function is responsible for removing a NetBIOS entry from
+the database. the name is searched for in the records using
+find_name_search(). if the ip is zero, then the ip is ignored.
+
+the name is removed if the expected source (e.g SELF, REGISTER)
+matches that in the database.
+
+
+/*************************************************************************
+ load_netbios_names()
+ *************************************************************************/
+
+this function is responsible for loading any NetBIOS names that samba,
+in its WINS capacity, has written out to disk. all the relevant details
+are recorded in this file, including the time-to-live. should the
+time left to live be small, the name is not added back in to samba's
+WINS database.
+
+
+/*************************************************************************
+ dump_names()
+ *************************************************************************/
+
+this function is responsible for outputting NetBIOS names in two formats.
+firstly, as debugging information, and secondly, all names that have been
+registered with samba in its capacity as a WINS server are written to
+disk.
+
+writing all WINS names allows two things. firstly, if samba's NetBIOS
+daemon dies or is terminated, on restarting the daemon most if not all
+of the registered WINS names will be preserved (which is a good reason
+why query_netbios_names() should be used).
+
+
+/*************************************************************************
+ find_name_search()
+ *************************************************************************/
+
+this function is a wrapper around find_name(). find_name_search() can
+be told whether to search for the name in a local subnet structure or
+in the WINS database. on top of this, it can be told to search only
+for samba's SELF names.
+
+if it finds the name in the WINS database, it will set the subnet_record
+and also return the name it finds.
+
+
+/*************************************************************************
+ find_name()
+ *************************************************************************/
+
+this function is a low-level search function that searches a single
+interface's NetBIOS records for a name. if the ip to be found is
+zero then the ip address is ignored. this is to enable a name to
+be found without knowing its ip address, and also to find the exact
+name if a large number of group names are added with different ip
+addresses.
+
+
+/*************************************************************************
+ remove_name()
+ *************************************************************************/
+
+this function is responsible for removing a specific NetBIOS entry
+from a subnet list's records. only if the pointer to the entry is
+in the list will the name be removed.
+
+
+/*************************************************************************
+ add_name()
+ *************************************************************************/
+
+this function is responsible for adding a NetBIOS entry into a
+subnet list's records.
+
+
+/*************************************************************************
+ ms_browser_name()
+ *************************************************************************/
+
+this function returns True if the NetBIOS name passed to it is
+^1^2__MSBROWSE__^2^1
+
+
+/*************************************************************************
+ name_equal()
+ *************************************************************************/
+
+this function returns True if the two NetBIOS names passed to it
+match in name, type and scope: the NetBIOS names are equal.
+
+
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/namedbresp.c samba-1.9.16alpha11/source/namedbresp.c
--- samba-1.9.16alpha10/source/namedbresp.c Thu Jan 1 10:00:00 1970
+++ samba-1.9.16alpha11/source/namedbresp.c Wed Jul 10 04:01:24 1996
@@ -0,0 +1,156 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios library routines
+ Copyright (C) Andrew Tridgell 1994-1996
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Module name: namedbresp.c
+
+*/
+
+#include "includes.h"
+
+extern int ClientNMB;
+extern int ClientDGRAM;
+
+extern struct subnet_record *subnetlist;
+
+extern int DEBUGLEVEL;
+
+extern pstring scope;
+extern pstring myname;
+extern struct in_addr ipzero;
+extern struct in_addr ipgrp;
+
+int num_response_packets = 0;
+
+/***************************************************************************
+ add an expected response record into the list
+ **************************************************************************/
+void add_response_record(struct subnet_record *d,
+ struct response_record *n)
+{
+ struct response_record *n2;
+
+ if (!d) return;
+
+ num_response_packets++; /* count of total number of packets still around */
+
+ DEBUG(4,("adding response record id:%d num_records:%d\n",
+ n->response_id, num_response_packets));
+
+ if (!d->responselist)
+ {
+ d->responselist = n;
+ n->prev = NULL;
+ n->next = NULL;
+ return;
+ }
+
+ for (n2 = d->responselist; n2->next; n2 = n2->next) ;
+
+ n2->next = n;
+ n->next = NULL;
+ n->prev = n2;
+}
+
+
+/***************************************************************************
+ remove an expected response record from the list
+ **************************************************************************/
+void remove_response_record(struct subnet_record *d,
+ struct response_record *n)
+{
+ if (!d) return;
+
+ if (n->prev) n->prev->next = n->next;
+ if (n->next) n->next->prev = n->prev;
+
+ if (d->responselist == n) d->responselist = n->next;
+
+ free(n);
+
+ num_response_packets--; /* count of total number of packets still around */
+}
+
+
+/****************************************************************************
+ create a name query response record
+ **************************************************************************/
+struct response_record *make_response_queue_record(enum state_type state,
+ int id,uint16 fd,
+ int quest_type, char *name,int type, int nb_flags, time_t ttl,
+ BOOL bcast,BOOL recurse,
+ struct in_addr send_ip, struct in_addr reply_to_ip)
+{
+ struct response_record *n;
+
+ if (!name || !name[0]) return NULL;
+
+ if (!(n = (struct response_record *)malloc(sizeof(*n))))
+ return(NULL);
+
+ n->response_id = id;
+ n->state = state;
+ n->fd = fd;
+ n->quest_type = quest_type;
+ make_nmb_name(&n->name, name, type, scope);
+ n->nb_flags = nb_flags;
+ n->ttl = ttl;
+ n->bcast = bcast;
+ n->recurse = recurse;
+ n->send_ip = send_ip;
+ n->reply_to_ip = reply_to_ip;
+
+ n->repeat_interval = 1; /* XXXX should be in ms */
+ n->repeat_count = 3; /* 3 retries */
+ n->repeat_time = time(NULL) + n->repeat_interval; /* initial retry time */
+
+ n->num_msgs = 0;
+
+ return n;
+}
+
+
+/****************************************************************************
+ find a response in a subnet's name query response list.
+ **************************************************************************/
+struct response_record *find_response_record(struct subnet_record **d,
+ uint16 id)
+{
+ struct response_record *n;
+
+ if (!d) return NULL;
+
+ for ((*d) = subnetlist; (*d); (*d) = (*d)->next)
+ {
+ for (n = (*d)->responselist; n; n = n->next)
+ {
+ if (n->response_id == id) {
+ DEBUG(4, ("found response record on %s: %d\n",
+ inet_ntoa((*d)->bcast_ip), id));
+ return n;
+ }
+ }
+ }
+
+ *d = NULL;
+
+ return NULL;
+}
+
+
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/namedbresp.doc samba-1.9.16alpha11/source/namedbresp.doc
--- samba-1.9.16alpha10/source/namedbresp.doc Thu Jan 1 10:00:00 1970
+++ samba-1.9.16alpha11/source/namedbresp.doc Thu Jul 11 04:48:26 1996
@@ -0,0 +1,48 @@
+module namedbresp deals with the maintenance of the list of expected
+responses - creating, finding and removal.
+
+module nameresp deals with the initial transmission, re-transmission
+and time-out of netbios response records.
+
+
+/*************************************************************************
+ find_response_record()
+ *************************************************************************/
+
+this function is responsible for matching the unique response transaction
+id with an expected response record. as a side-effect of this search,
+it will find the subnet (or the WINS pseudo-subnet) that samba expected
+the response to come from.
+
+
+/*************************************************************************
+ make_response_queue_record()
+ *************************************************************************/
+
+this function is responsible for creating a response record, which will
+be queued awaiting a response.
+
+the number of retries is set to 3, and the retry period set to 1 second.
+if no response is received, then the packet is re-transmitted, which is
+why so much information is stored in the response record.
+
+the number of expected responses queued is kept, so listen_for_packets()
+knows it must time-out after 1 second if one or more responses are
+expected.
+
+
+/*************************************************************************
+ remove_response_record()
+ *************************************************************************/
+
+this function is responsible for removing a response record from the
+expected response queue. the number of expected responses is decreased.
+
+
+/*************************************************************************
+ add_response_record()
+ *************************************************************************/
+
+this function is responsible for adding the response record created by
+make_response_queue_record() into the appropriate response record queue.
+
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/namedbserver.c samba-1.9.16alpha11/source/namedbserver.c
--- samba-1.9.16alpha10/source/namedbserver.c Thu Jan 1 10:00:00 1970
+++ samba-1.9.16alpha11/source/namedbserver.c Thu Jul 18 20:53:15 1996
@@ -0,0 +1,221 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1996
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Revision History:
+
+ 14 jan 96: lkcl@pires.co.uk
+ added multiple workgroup domain master support
+
+ 04 jul 96: lkcl@pires.co.uk
+ created module namedbserver containing server database functions
+
+*/
+
+#include "includes.h"
+#include "smb.h"
+
+extern int ClientNMB;
+extern int ClientDGRAM;
+
+extern int DEBUGLEVEL;
+
+extern pstring myname;
+
+/* this is our domain/workgroup/server database */
+extern struct subnet_record *subnetlist;
+
+extern BOOL updatedlists;
+
+
+/*******************************************************************
+ expire old servers in the serverlist
+ time of -1 indicates everybody dies except those with time of 0
+ remove_all_servers indicates everybody dies.
+ ******************************************************************/
+void remove_old_servers(struct work_record *work, time_t t,
+ BOOL remove_all)
+{
+ struct server_record *s;
+ struct server_record *nexts;
+
+ /* expire old entries in the serverlist */
+ for (s = work->serverlist; s; s = nexts)
+ {
+ if (remove_all || (s->death_time && (t == -1 || s->death_time < t)))
+ {
+ DEBUG(3,("Removing dead server %s\n",s->serv.name));
+ updatedlists = True;
+ nexts = s->next;
+
+ if (s->prev) s->prev->next = s->next;
+ if (s->next) s->next->prev = s->prev;
+
+ if (work->serverlist == s)
+ work->serverlist = s->next;
+
+ free(s);
+ }
+ else
+ {
+ nexts = s->next;
+ }
+ }
+}
+
+
+/***************************************************************************
+ add a server into the list
+ **************************************************************************/
+static void add_server(struct work_record *work,struct server_record *s)
+{
+ struct server_record *s2;
+
+ if (!work->serverlist) {
+ work->serverlist = s;
+ s->prev = NULL;
+ s->next = NULL;
+ return;
+ }
+
+ for (s2 = work->serverlist; s2->next; s2 = s2->next) ;
+
+ s2->next = s;
+ s->next = NULL;
+ s->prev = s2;
+}
+
+
+/****************************************************************************
+ find a server in a server list.
+ **************************************************************************/
+struct server_record *find_server(struct work_record *work, char *name)
+{
+ struct server_record *ret;
+
+ if (!work) return NULL;
+
+ for (ret = work->serverlist; ret; ret = ret->next)
+ {
+ if (strequal(ret->serv.name,name))
+ {
+ return ret;
+ }
+ }
+ return NULL;
+}
+
+
+/****************************************************************************
+ add a server entry
+ ****************************************************************************/
+struct server_record *add_server_entry(struct subnet_record *d,
+ struct work_record *work,
+ char *name,int servertype,
+ int ttl,char *comment,
+ BOOL replace)
+{
+ BOOL newentry=False;
+ struct server_record *s;
+
+ if (name[0] == '*')
+ {
+ return (NULL);
+ }
+
+ s = find_server(work, name);
+
+ if (s && !replace)
+ {
+ DEBUG(4,("Not replacing %s\n",name));
+ return(s);
+ }
+
+ if (!s || s->serv.type != servertype || !strequal(s->serv.comment, comment))
+ updatedlists=True;
+
+ if (!s)
+ {
+ newentry = True;
+ s = (struct server_record *)malloc(sizeof(*s));
+
+ if (!s) return(NULL);
+
+ bzero((char *)s,sizeof(*s));
+ }
+
+
+ if (d->my_interface && strequal(lp_workgroup(),work->work_group))
+ {
+ if (servertype)
+ servertype |= SV_TYPE_LOCAL_LIST_ONLY;
+ }
+ else
+ {
+ servertype &= ~SV_TYPE_LOCAL_LIST_ONLY;
+ }
+
+ /* update the entry */
+ StrnCpy(s->serv.name,name,sizeof(s->serv.name)-1);
+ StrnCpy(s->serv.comment,comment,sizeof(s->serv.comment)-1);
+ strupper(s->serv.name);
+ s->serv.type = servertype;
+ s->death_time = servertype ? (ttl?time(NULL)+ttl*3:0) : (time(NULL)-1);
+
+ /* for a domain entry, the comment field refers to the server name */
+
+ if (s->serv.type & SV_TYPE_DOMAIN_ENUM) strupper(s->serv.comment);
+
+ if (newentry)
+ {
+ add_server(work, s);
+
+ DEBUG(3,("Added "));
+ }
+ else
+ {
+ DEBUG(3,("Updated "));
+ }
+
+ DEBUG(3,("server entry %s of type %x (%s) to %s %s\n",
+ name,servertype,comment,
+ work->work_group,inet_ntoa(d->bcast_ip)));
+
+ return(s);
+}
+
+
+/*******************************************************************
+ expire old servers in the serverlist
+ ******************************************************************/
+void expire_servers(time_t t)
+{
+ struct subnet_record *d;
+
+ for (d = subnetlist ; d ; d = d->next)
+ {
+ struct work_record *work;
+
+ for (work = d->workgrouplist; work; work = work->next)
+ {
+ remove_old_servers(work, t, False);
+ }
+ }
+}
+
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/namedbsubnet.c samba-1.9.16alpha11/source/namedbsubnet.c
--- samba-1.9.16alpha10/source/namedbsubnet.c Thu Jan 1 10:00:00 1970
+++ samba-1.9.16alpha11/source/namedbsubnet.c Thu Jul 11 04:48:26 1996
@@ -0,0 +1,346 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1996
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Revision History:
+
+ 14 jan 96: lkcl@pires.co.uk
+ added multiple workgroup domain master support
+
+ 04 jul 96: lkcl@pires.co.uk
+ created module namedbsubnet containing subnet database functions
+
+*/
+
+#include "includes.h"
+#include "smb.h"
+
+extern int ClientNMB;
+extern int ClientDGRAM;
+
+extern int DEBUGLEVEL;
+
+extern struct in_addr ipgrp;
+extern struct in_addr ipzero;
+
+extern pstring myname;
+
+BOOL updatedlists = True;
+int updatecount = 0;
+
+/* local interfaces structure */
+extern struct interface *local_interfaces;
+
+/* remote interfaces structure */
+extern struct interface *remote_interfaces;
+
+/* this is our domain/workgroup/server database */
+struct subnet_record *subnetlist = NULL;
+
+
+/****************************************************************************
+ add a domain into the list
+ **************************************************************************/
+static void add_subnet(struct subnet_record *d)
+{
+ struct subnet_record *d2;
+
+ if (!subnetlist)
+ {
+ subnetlist = d;
+ d->prev = NULL;
+ d->next = NULL;
+ return;
+ }
+
+ for (d2 = subnetlist; d2->next; d2 = d2->next);
+
+ d2->next = d;
+ d->next = NULL;
+ d->prev = d2;
+}
+
+
+/****************************************************************************
+ find a subnet in the subnetlist
+ **************************************************************************/
+struct subnet_record *find_subnet(struct in_addr bcast_ip)
+{
+ struct subnet_record *d;
+ struct in_addr wins_ip = ipgrp;
+
+ /* search through subnet list for broadcast/netmask that matches
+ the source ip address. a subnet 255.255.255.255 represents the
+ WINS list. */
+
+ for (d = subnetlist; d; d = d->next)
+ {
+ if (ip_equal(bcast_ip, wins_ip))
+ {
+ if (ip_equal(bcast_ip, d->bcast_ip))
+ {
+ return d;
+ }
+ }
+ else if (same_net(bcast_ip, d->bcast_ip, d->mask_ip))
+ {
+ return(d);
+ }
+ }
+
+ return (NULL);
+}
+
+
+/****************************************************************************
+ finds the appropriate subnet structure. directed packets (non-bcast) are
+ assumed to come from a point-to-point (P or M node), and so the subnet we
+ return in this instance is the WINS 'pseudo-subnet' with ip 255.255.255.255
+ ****************************************************************************/
+struct subnet_record *find_req_subnet(struct in_addr ip, BOOL bcast)
+{
+ if (bcast)
+ {
+ /* identify the subnet the broadcast request came from */
+ return find_subnet(*iface_bcast(ip));
+ }
+ /* find the subnet under the pseudo-ip of 255.255.255.255 */
+ return find_subnet(ipgrp);
+}
+
+
+/****************************************************************************
+ create a domain entry
+ ****************************************************************************/
+static struct subnet_record *make_subnet(struct in_addr bcast_ip, struct in_addr mask_ip)
+{
+ struct subnet_record *d;
+ d = (struct subnet_record *)malloc(sizeof(*d));
+
+ if (!d) return(NULL);
+
+ bzero((char *)d,sizeof(*d));
+
+ DEBUG(4, ("making domain %s ", inet_ntoa(bcast_ip)));
+ DEBUG(4, ("%s\n", inet_ntoa(mask_ip)));
+
+ d->bcast_ip = bcast_ip;
+ d->mask_ip = mask_ip;
+ d->workgrouplist = NULL;
+ d->my_interface = False; /* True iff the interface is on the samba host */
+
+ add_subnet(d);
+
+ return d;
+}
+
+
+/****************************************************************************
+ add the remote interfaces from lp_remote_interfaces() and lp_interfaces()
+ to the netbios subnet database.
+ ****************************************************************************/
+void add_subnet_interfaces(void)
+{
+ struct interface *i;
+
+ /* loop on all local interfaces */
+ for (i = local_interfaces; i; i = i->next)
+ {
+ /* add the interface into our subnet database */
+ if (!find_subnet(i->bcast))
+ {
+ struct subnet_record *d = make_subnet(i->bcast,i->nmask);
+ if (d)
+ {
+ /* short-cut method to identifying local interfaces */
+ d->my_interface = True;
+ }
+ }
+ }
+
+ /* loop on all remote interfaces */
+ for (i = remote_interfaces; i; i = i->next)
+ {
+ /* add the interface into our subnet database */
+ if (!find_subnet(i->bcast))
+ {
+ make_subnet(i->bcast,i->nmask);
+ }
+ }
+
+ /* add the pseudo-ip interface for WINS: 255.255.255.255 */
+ if (lp_wins_support())
+ {
+ struct in_addr wins_bcast = ipgrp;
+ struct in_addr wins_nmask = ipzero;
+ make_subnet(wins_bcast, wins_nmask);
+ }
+}
+
+
+
+/****************************************************************************
+ add the default workgroup into my domain
+ **************************************************************************/
+void add_my_subnets(char *group)
+{
+ struct interface *i;
+
+ /* add or find domain on our local subnet, in the default workgroup */
+
+ if (*group == '*') return;
+
+ /* the coding choice is up to you, andrew: i can see why you don't want
+ global access to the local_interfaces structure: so it can't get
+ messed up! */
+ for (i = local_interfaces; i; i = i->next)
+ {
+ add_subnet_entry(i->bcast,i->nmask,group, True, False);
+ }
+}
+
+
+/****************************************************************************
+ add a domain entry. creates a workgroup, if necessary, and adds the domain
+ to the named a workgroup.
+ ****************************************************************************/
+struct subnet_record *add_subnet_entry(struct in_addr bcast_ip,
+ struct in_addr mask_ip,
+ char *name, BOOL add, BOOL lmhosts)
+{
+ struct subnet_record *d;
+
+ /* XXXX andrew: struct in_addr ip appears not to be referenced at all except
+ in the DEBUG comment. i assume that the DEBUG comment below actually
+ intends to refer to bcast_ip? i don't know.
+
+ struct in_addr ip = ipgrp;
+
+ */
+
+ if (zero_ip(bcast_ip))
+ bcast_ip = *iface_bcast(bcast_ip);
+
+ /* add the domain into our domain database */
+ if ((d = find_subnet(bcast_ip)) ||
+ (d = make_subnet(bcast_ip, mask_ip)))
+ {
+ struct work_record *w = find_workgroupstruct(d, name, add);
+ extern pstring ServerComment;
+
+ if (!w) return NULL;
+
+ /* add WORKGROUP(1e) and WORKGROUP(00) entries into name database
+ or register with WINS server, if it's our workgroup */
+ if (strequal(lp_workgroup(), name) && d->my_interface)
+ {
+ add_my_name_entry(d,name,0x1e,NB_ACTIVE|NB_GROUP);
+ add_my_name_entry(d,name,0x0 ,NB_ACTIVE|NB_GROUP);
+ }
+ /* add samba server name to workgroup list. don't add
+ lmhosts server entries to local interfaces */
+ if ((strequal(lp_workgroup(), name) && d->my_interface) ||
+ (lmhosts && !d->my_interface))
+ {
+ add_server_entry(d,w,myname,w->ServerType,0,ServerComment,True);
+ DEBUG(3,("Added server name entry %s at %s\n",
+ name,inet_ntoa(bcast_ip)));
+ }
+
+ return d;
+ }
+ return NULL;
+}
+
+
+/*******************************************************************
+ write out browse.dat
+ ******************************************************************/
+void write_browse_list(void)
+{
+ struct subnet_record *d;
+ pstring fname,fnamenew;
+ FILE *f;
+
+ static time_t lasttime = 0;
+ time_t t = time(NULL);
+
+ if (!lasttime) lasttime = t;
+ if (!updatedlists || t - lasttime < 5) return;
+
+ lasttime = t;
+ updatedlists = False;
+ updatecount++;
+
+ dump_names();
+ dump_workgroups();
+
+ strcpy(fname,lp_lockdir());
+ trim_string(fname,NULL,"/");
+ strcat(fname,"/");
+ strcat(fname,SERVER_LIST);
+ strcpy(fnamenew,fname);
+ strcat(fnamenew,".");
+
+ f = fopen(fnamenew,"w");
+
+ if (!f)
+ {
+ DEBUG(4,("Can't open %s - %s\n",fnamenew,strerror(errno)));
+ return;
+ }
+
+ for (d = subnetlist; d ; d = d->next)
+ {
+ struct work_record *work;
+ for (work = d->workgrouplist; work ; work = work->next)
+ {
+ struct server_record *s;
+ for (s = work->serverlist; s ; s = s->next)
+ {
+ fstring tmp;
+
+ /* don't list domains I don't have a master for */
+ if ((s->serv.type & SV_TYPE_DOMAIN_ENUM) && !s->serv.comment[0])
+ {
+ continue;
+ }
+
+ /* output server details, plus what workgroup/domain
+ they're in. without the domain information, the
+ combined list of all servers in all workgroups gets
+ sent to anyone asking about any workgroup! */
+
+ sprintf(tmp, "\"%s\"", s->serv.name);
+ fprintf(f, "%-25s ", tmp);
+ fprintf(f, "%08x ", s->serv.type);
+ sprintf(tmp, "\"%s\" ", s->serv.comment);
+ fprintf(f, "%-30s", tmp);
+ fprintf(f, "\"%s\"\n", work->work_group);
+ }
+ }
+ }
+
+ fclose(f);
+ unlink(fname);
+ chmod(fnamenew,0644);
+ rename(fnamenew,fname);
+ DEBUG(3,("Wrote browse list %s\n",fname));
+}
+
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/namedbwork.c samba-1.9.16alpha11/source/namedbwork.c
--- samba-1.9.16alpha10/source/namedbwork.c Thu Jan 1 10:00:00 1970
+++ samba-1.9.16alpha11/source/namedbwork.c Wed Jul 10 04:01:25 1996
@@ -0,0 +1,255 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1996
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Revision History:
+
+ 14 jan 96: lkcl@pires.co.uk
+ added multiple workgroup domain master support
+
+ 04 jul 96: lkcl@pires.co.uk
+ created module namedbwork containing workgroup database functions
+
+*/
+
+#include "includes.h"
+#include "smb.h"
+
+extern int ClientNMB;
+
+extern int DEBUGLEVEL;
+
+/* this is our domain/workgroup/server database */
+extern struct subnet_record *subnetlist;
+
+int workgroup_count = 0; /* unique index key: one for each workgroup */
+
+/* what server type are we currently */
+
+#define DFLT_SERVER_TYPE (SV_TYPE_WORKSTATION | SV_TYPE_SERVER | \
+ SV_TYPE_TIME_SOURCE | SV_TYPE_SERVER_UNIX | \
+ SV_TYPE_PRINTQ_SERVER | SV_TYPE_POTENTIAL_BROWSER)
+
+
+/****************************************************************************
+ add a workgroup into the domain list
+ **************************************************************************/
+static void add_workgroup(struct work_record *work, struct subnet_record *d)
+{
+ struct work_record *w2;
+
+ if (!work || !d) return;
+
+ if (!d->workgrouplist)
+ {
+ d->workgrouplist = work;
+ work->prev = NULL;
+ work->next = NULL;
+ return;
+ }
+
+ for (w2 = d->workgrouplist; w2->next; w2 = w2->next);
+
+ w2->next = work;
+ work->next = NULL;
+ work->prev = w2;
+}
+
+
+/****************************************************************************
+ create a blank workgroup
+ **************************************************************************/
+static struct work_record *make_workgroup(char *name)
+{
+ struct work_record *work;
+ struct subnet_record *d;
+ int t = -1;
+
+ if (!name || !name[0]) return NULL;
+
+ work = (struct work_record *)malloc(sizeof(*work));
+ if (!work) return(NULL);
+
+ StrnCpy(work->work_group,name,sizeof(work->work_group)-1);
+ work->serverlist = NULL;
+
+ work->ServerType = DFLT_SERVER_TYPE;
+ work->RunningElection = False;
+ work->ElectionCount = 0;
+ work->needelection = False;
+ work->needannounce = True;
+ work->state = MST_NONE;
+
+ /* make sure all token representations of workgroups are unique */
+
+ for (d = subnetlist; d && t == -1; d = d->next)
+ {
+ struct work_record *w;
+ for (w = d->workgrouplist; w && t == -1; w = w->next)
+ {
+ if (strequal(w->work_group, work->work_group)) t = w->token;
+ }
+ }
+
+ if (t == -1)
+ {
+ work->token = ++workgroup_count;
+ }
+ else
+ {
+ work->token = t;
+ }
+
+
+ /* WfWg uses 01040b01 */
+ /* Win95 uses 01041501 */
+ /* NTAS uses ???????? */
+ work->ElectionCriterion = (MAINTAIN_LIST<<1)|(ELECTION_VERSION<<8);
+ work->ElectionCriterion |= (lp_os_level() << 24);
+ if (lp_domain_master()) {
+ work->ElectionCriterion |= 0x80;
+ }
+
+ return work;
+}
+
+
+/*******************************************************************
+ remove workgroups
+ ******************************************************************/
+struct work_record *remove_workgroup(struct subnet_record *d,
+ struct work_record *work,
+ BOOL remove_all_servers)
+{
+ struct work_record *ret_work = NULL;
+
+ if (!d || !work) return NULL;
+
+ DEBUG(3,("Removing old workgroup %s\n", work->work_group));
+
+ ret_work = work->next;
+
+ remove_old_servers(work, -1, remove_all_servers);
+
+ if (!work->serverlist)
+ {
+ if (work->prev) work->prev->next = work->next;
+ if (work->next) work->next->prev = work->prev;
+
+ if (d->workgrouplist == work) d->workgrouplist = work->next;
+
+ free(work);
+ }
+
+ return ret_work;
+}
+
+
+/****************************************************************************
+ find a workgroup in the workgrouplist
+ only create it if the domain allows it, or the parameter 'add' insists
+ that it get created/added anyway. this allows us to force entries in
+ lmhosts file to be added.
+ **************************************************************************/
+struct work_record *find_workgroupstruct(struct subnet_record *d,
+ fstring name, BOOL add)
+{
+ struct work_record *ret, *work;
+
+ if (!d) return NULL;
+
+ DEBUG(4, ("workgroup search for %s: ", name));
+
+ if (strequal(name, "*"))
+ {
+ DEBUG(2,("add any workgroups: initiating browser search on %s\n",
+ inet_ntoa(d->bcast_ip)));
+ queue_netbios_pkt_wins(d,ClientNMB,NMB_QUERY, NAME_QUERY_FIND_MST,
+ MSBROWSE,0x1,0,0,
+ True,False, d->bcast_ip, d->bcast_ip);
+ return NULL;
+ }
+
+ for (ret = d->workgrouplist; ret; ret = ret->next) {
+ if (!strcmp(ret->work_group,name)) {
+ DEBUG(4, ("found\n"));
+ return(ret);
+ }
+ }
+
+ if (!add) {
+ DEBUG(4, ("not found\n"));
+ return NULL;
+ }
+
+ DEBUG(4,("not found: creating\n"));
+
+ if ((work = make_workgroup(name)))
+ {
+ if (lp_preferred_master() &&
+ strequal(lp_workgroup(), name) &&
+ d->my_interface)
+ {
+ DEBUG(3, ("preferred master startup for %s\n", work->work_group));
+ work->needelection = True;
+ work->ElectionCriterion |= (1<<3);
+ }
+ if (!d->my_interface)
+ {
+ work->needelection = False;
+ }
+ add_workgroup(work, d);
+ return(work);
+ }
+ return NULL;
+}
+
+
+/****************************************************************************
+ dump a copy of the workgroup/domain database
+ **************************************************************************/
+void dump_workgroups(void)
+{
+ struct subnet_record *d;
+
+ for (d = subnetlist; d; d = d->next)
+ {
+ if (d->workgrouplist)
+ {
+ struct work_record *work;
+
+ DEBUG(4,("dump domain bcast=%15s: ", inet_ntoa(d->bcast_ip)));
+ DEBUG(4,(" netmask=%15s:\n", inet_ntoa(d->mask_ip)));
+
+ for (work = d->workgrouplist; work; work = work->next)
+ {
+ DEBUG(4,("\t%s(%d)\n", work->work_group, work->token));
+ if (work->serverlist)
+ {
+ struct server_record *s;
+ for (s = work->serverlist; s; s = s->next)
+ {
+ DEBUG(4,("\t\t%s %8x (%s)\n",
+ s->serv.name, s->serv.type, s->serv.comment));
+ }
+ }
+ }
+ }
+ }
+}
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/nameelect.c samba-1.9.16alpha11/source/nameelect.c
--- samba-1.9.16alpha10/source/nameelect.c Mon Jun 10 15:18:56 1996
+++ samba-1.9.16alpha11/source/nameelect.c Thu Jul 18 20:53:15 1996
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
NBT netbios routines and daemon - version 2
- Copyright (C) Andrew Tridgell 1994-1995
+ Copyright (C) Andrew Tridgell 1994-1996
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,11 +18,17 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ Module name: nameelect.c
+
Revision History:
14 jan 96: lkcl@pires.co.uk
added multiple workgroup domain master support
+ 04 jul 96: lkcl@pires.co.uk
+ added system to become a master browser by stages.
+
+
*/
#include "includes.h"
@@ -34,6 +40,8 @@
extern pstring scope;
extern pstring myname;
+extern struct in_addr ipzero;
+extern struct in_addr ipgrp;
/* machine comment for host announcements */
extern pstring ServerComment;
@@ -42,10 +50,6 @@
extern time_t StartupTime;
-#define AM_MASTER(work) (work->ServerType & SV_TYPE_MASTER_BROWSER)
-
-#define BROWSE_MAILSLOT "\\MAILSLOT\\BROWSE"
-
extern struct subnet_record *subnetlist;
@@ -59,9 +63,8 @@
struct subnet_record *d;
if (!lastrun) lastrun = t;
- if (t < lastrun + CHECK_TIME_MST_BROWSE * 60)
+ if (t < lastrun + CHECK_TIME_MST_BROWSE * 60)
return;
-
lastrun = t;
dump_workgroups();
@@ -77,9 +80,9 @@
if (!AM_MASTER(work))
{
- queue_netbios_packet(ClientNMB,NMB_QUERY,CHECK_MASTER,
- work->work_group,0x1d,0,
- True,False,d->bcast_ip);
+ queue_netbios_packet(d,ClientNMB,NMB_QUERY,NAME_QUERY_MST_CHK,
+ work->work_group,0x1d,0,0,
+ True,False,d->bcast_ip,d->bcast_ip);
}
}
}
@@ -91,36 +94,38 @@
******************************************************************/
void browser_gone(char *work_name, struct in_addr ip)
{
- struct subnet_record *d = find_domain(ip);
+ struct subnet_record *d = find_subnet(ip);
struct work_record *work = find_workgroupstruct(d, work_name, False);
+ /* i don't know about this workgroup, therefore i don't care */
if (!work || !d) return;
-
- if (strequal(work->work_group, lp_workgroup()) &&
- d->my_interface)
- {
+
+ if (strequal(work->work_group, lp_workgroup()) && d->my_interface)
+ {
DEBUG(2,("Forcing election on %s %s\n",
work->work_group,inet_ntoa(d->bcast_ip)));
/* we can attempt to become master browser */
work->needelection = True;
- }
+ }
else
- {
- /* XXXX note: this will delete entries that have been added in by
- lmhosts as well. a flag to ensure that these are not deleted may
- be considered */
-
- /* workgroup with no master browser is not the default workgroup:
- it's also not on our subnet. therefore delete it: it can be
- recreated dynamically */
-
- send_election(d, work->work_group, 0, 0, myname);
- remove_workgroup(d, work);
- }
+ {
+ /* local interfaces: force an election */
+ if (d->my_interface)
+ send_election(d, work->work_group, 0, 0, myname);
+
+ /* only removes workgroup completely on a local interface or
+ if there are no server entries on the remote interface.
+ (persistent lmhost entries on a remote interface will stop
+ the workgroup being removed. persistent lmhosts entries on
+ a local interface _will_ be removed).
+ */
+ remove_workgroup(d, work, d->my_interface);
+ }
}
+
/****************************************************************************
send an election packet
**************************************************************************/
@@ -137,7 +142,7 @@
bzero(outbuf,sizeof(outbuf));
p = outbuf;
- CVAL(p,0) = 8; /* election */
+ CVAL(p,0) = ANN_Election; /* election */
p++;
CVAL(p,0) = (criterion == 0 && timeup == 0) ? 0 : ELECTION_VERSION;
@@ -153,68 +158,318 @@
}
+/****************************************************************************
+ un-register a SELF name that got rejected.
+
+ if this name happens to be rejected when samba is in the process
+ of becoming a master browser (registering __MSBROWSE__, WORKGROUP(1d)
+ or WORKGROUP(1b)) then we must stop being a master browser. sad.
+
+ **************************************************************************/
+void name_unregister_work(struct subnet_record *d, char *name, int name_type)
+{
+ struct work_record *work;
+
+ remove_netbios_name(d,name,name_type,SELF,ipzero);
+
+ if (!(work = find_workgroupstruct(d, name, False))) return;
+
+ if (ms_browser_name(name, name_type) ||
+ (AM_MASTER(work) && strequal(name, lp_workgroup()) == 0 &&
+ (name_type == 0x1d || name_type == 0x1b)))
+ {
+ int remove_type = 0;
+
+ if (ms_browser_name(name, name_type))
+ remove_type = SV_TYPE_MASTER_BROWSER|SV_TYPE_DOMAIN_MASTER;
+ if (name_type == 0x1d)
+ remove_type = SV_TYPE_MASTER_BROWSER;
+ if (name_type == 0x1b)
+ remove_type = SV_TYPE_DOMAIN_MASTER;
+
+ become_nonmaster(d, work, remove_type);
+ }
+}
+
+
+/****************************************************************************
+ registers a name.
+
+ if the name being added is a SELF name, we must additionally check
+ whether to proceed to the next stage in samba becoming a master browser.
+
+ **************************************************************************/
+void name_register_work(struct subnet_record *d, char *name, int name_type,
+ int nb_flags, time_t ttl, struct in_addr ip, BOOL bcast)
+{
+ enum name_source source = (ismyip(ip) || ip_equal(ip, ipzero)) ?
+ SELF : REGISTER;
+
+ if (source == SELF)
+ {
+ struct work_record *work = find_workgroupstruct(d, lp_workgroup(), False);
+
+ add_netbios_entry(d,name,name_type,nb_flags,ttl,source,ip,True,!bcast);
+
+ if (work)
+ {
+ if (work->state != MST_NONE)
+ {
+ /* samba is in the process of working towards master browser-ness.
+ initiate the next stage.
+ */
+ become_master(d, work);
+ return;
+ }
+ }
+ }
+}
+
+
/*******************************************************************
- become the master browser
+ become the master browser.
+
+ this is done in stages. note that this could take a while,
+ particularly on a broadcast subnet, as we have to wait for
+ the implicit registration of each name to be accepted.
+
+ as each name is successfully registered, become_master() is
+ called again, in order to initiate the next stage. see
+ dead_netbios_entry() - deals with implicit name registration
+ and response_name_reg() - deals with explicit registration
+ with a WINS server.
+
+ stage 1: was MST_NONE - go to MST_NONE and register ^1^2__MSBROWSE__^2^1.
+ stage 2: was MST_WON - go to MST_MSB and register WORKGROUP(0x1d)
+ stage 3: was MST_MSB - go to MST_BROWSER and register WORKGROUP(0x1b)
+ stage 4: was MST_BROWSER - go to MST_DOMAIN (do not pass GO, do not...)
+
+ XXXX note: this code still does not cope with the distinction
+ between different types of nodes, particularly between M and P
+ nodes. that comes later.
+
******************************************************************/
-static void become_master(struct subnet_record *d, struct work_record *work)
+void become_master(struct subnet_record *d, struct work_record *work)
{
- uint32 domain_type = SV_TYPE_DOMAIN_ENUM | SV_TYPE_SERVER_UNIX | 0x00400000;
+ uint32 domain_type = SV_TYPE_DOMAIN_ENUM|SV_TYPE_SERVER_UNIX|0x00400000;
if (!work) return;
- DEBUG(2,("Becoming master for %s\n",work->work_group));
+ DEBUG(2,("Becoming master for %s %s (currently at stage %d)\n",
+ work->work_group,inet_ntoa(d->bcast_ip),work->state));
- work->ServerType |= SV_TYPE_MASTER_BROWSER;
- work->ServerType &= ~SV_TYPE_POTENTIAL_BROWSER;
- work->ElectionCriterion |= 0x5;
+ switch (work->state)
+ {
+ case MST_NONE: /* while we were nothing but a server... */
+ {
+ DEBUG(3,("go to first stage: register ^1^2__MSBROWSE__^2^1\n"));
+ work->state = MST_WON; /* ... an election win was successful */
+
+ work->ElectionCriterion |= 0x5;
+
+ /* update our server status */
+ work->ServerType &= ~SV_TYPE_POTENTIAL_BROWSER;
+ add_server_entry(d,work,myname,work->ServerType,0,ServerComment,True);
+
+ /* add special browser name */
+ add_my_name_entry(d,MSBROWSE ,0x01,NB_ACTIVE|NB_GROUP);
+
+ /* DON'T do anything else after calling add_my_name_entry() */
+ return;
+ }
+ case MST_WON: /* while nothing had happened except we won an election... */
+ {
+ DEBUG(3,("go to second stage: register as master browser\n"));
+ work->state = MST_MSB; /* ... registering MSBROWSE was successful */
+
+ /* add server entry on successful registration of MSBROWSE */
+ add_server_entry(d,work,work->work_group,domain_type,0,myname,True);
+
+ /* add master name */
+ add_my_name_entry(d,work->work_group,0x1d,NB_ACTIVE );
- /* add browse, master and general names to database or register with WINS */
- add_name_entry(MSBROWSE ,0x01,NB_ACTIVE|NB_GROUP);
- add_name_entry(work->work_group,0x1d,NB_ACTIVE );
+ /* DON'T do anything else after calling add_my_name_entry() */
+ return;
+ }
+ case MST_MSB: /* while we were still only registered MSBROWSE state... */
+ {
+ DEBUG(3,("2nd stage complete: registered as master browser\n"));
+ work->state = MST_BROWSER; /* ... registering WORKGROUP(1d) succeeded */
+
+ /* update our server status */
+ work->ServerType |= SV_TYPE_MASTER_BROWSER;
+ add_server_entry(d,work,myname,work->ServerType,0,ServerComment,True);
+
+ if (d->my_interface && work->serverlist == NULL) /* no servers! */
+ {
+ /* ask all servers on our local net to announce to us */
+ announce_request(work, d->bcast_ip);
+ }
+ break;
+ }
+
+ case MST_BROWSER:
+ {
+ /* don't have to do anything: just report success */
+ DEBUG(3,("3rd stage: become master browser!\n"));
+
+ break;
+ }
+
+ case MST_DOMAIN_NONE:
+ {
+ if (lp_domain_master())
+ {
+ work->state = MST_DOMAIN_MEM; /* ... become domain member */
+ DEBUG(3,("domain first stage: register as domain member\n"));
+
+ /* add domain member name */
+ add_my_name_entry(d,work->work_group,0x1e,NB_ACTIVE );
+
+ /* DON'T do anything else after calling add_my_name_entry() */
+ return;
+ }
+ else
+ {
+ DEBUG(4,("samba not configured as a domain master.\n"));
+ }
+
+ break;
+ }
+
+ case MST_DOMAIN_MEM:
+ {
+ if (lp_domain_master())
+ {
+ work->state = MST_DOMAIN_TST; /* ... possibly become domain master */
+ DEBUG(3,("domain second stage: register as domain master\n"));
+
+ if (lp_domain_logons())
+ {
+ work->ServerType |= SV_TYPE_DOMAIN_MEMBER;
+ add_server_entry(d,work,myname,work->ServerType,0,ServerComment,True);
+ }
+
+ /* add domain master name */
+ add_my_name_entry(d,work->work_group,0x1b,NB_ACTIVE );
+
+ /* DON'T do anything else after calling add_my_name_entry() */
+ return;
+ }
+ else
+ {
+ DEBUG(4,("samba not configured as a domain master.\n"));
+ }
- if (lp_domain_master())
+ break;
+ }
+
+ case MST_DOMAIN_TST: /* while we were still a master browser... */
{
- DEBUG(4,("Domain master: adding names...\n"));
-
- /* add domain master and domain member names or register with WINS */
- add_name_entry(work->work_group,0x1b,NB_ACTIVE);
- work->ServerType |= SV_TYPE_DOMAIN_MASTER;
+ /* update our server status */
+ if (lp_domain_master())
+ {
+ struct subnet_record *d1;
+ uint32 update_type = 0;
+
+ DEBUG(3,("domain third stage: samba is now a domain master.\n"));
+ work->state = MST_DOMAIN; /* ... registering WORKGROUP(1b) succeeded */
+
+ update_type |= SV_TYPE_DOMAIN_MASTER;
- if (lp_domain_logons())
- {
- work->ServerType |= SV_TYPE_DOMAIN_CTRL;
- work->ServerType |= SV_TYPE_DOMAIN_MEMBER;
- }
- }
-
- /* update our server status */
- add_server_entry(d,work,work->work_group,domain_type,0,myname,True);
- add_server_entry(d,work,myname,work->ServerType,0,ServerComment,True);
+ if (lp_domain_logons())
+ {
+ update_type |= SV_TYPE_DOMAIN_CTRL;
+ }
+
+ work->ServerType |= update_type;
+ add_server_entry(d,work,myname,work->ServerType,0,ServerComment,True);
+
+ for (d1 = subnetlist; d1; d1 = d1->next)
+ {
+ struct work_record *w;
+ if (ip_equal(d1->bcast_ip, d->bcast_ip)) continue;
+
+ for (w = d1->workgrouplist; w; w = w->next)
+ {
+ struct server_record *s = find_server(w, myname);
+ if (strequal(w->work_group, work->work_group))
+ {
+ w->ServerType |= update_type;
+ }
+ if (s)
+ {
+ s->serv.type |= update_type;
+ DEBUG(4,("found server %s on %s: update to %8x\n",
+ s->serv.name, inet_ntoa(d1->bcast_ip),
+ s->serv.type));
+ }
+ }
+ }
+ }
- if (d->my_interface)
+ break;
+ }
+
+ case MST_DOMAIN:
{
- /* ask all servers on our local net to announce to us */
- announce_request(work, d->bcast_ip);
+ /* don't have to do anything: just report success */
+ DEBUG(3,("fifth stage: there isn't one yet!\n"));
+ break;
}
+ }
}
/*******************************************************************
- unbecome the master browser
+ unbecome the master browser. initates removal of necessary netbios
+ names, and tells the world that we are no longer a master browser.
******************************************************************/
-void become_nonmaster(struct subnet_record *d, struct work_record *work)
+void become_nonmaster(struct subnet_record *d, struct work_record *work,
+ int remove_type)
{
+ int new_server_type = work->ServerType;
+
DEBUG(2,("Becoming non-master for %s\n",work->work_group));
- work->ServerType &= ~SV_TYPE_MASTER_BROWSER;
- work->ServerType &= ~SV_TYPE_DOMAIN_MASTER;
- work->ServerType |= SV_TYPE_POTENTIAL_BROWSER;
-
- work->ElectionCriterion &= ~0x4;
-
- remove_name_entry(work->work_group,0x1b);
- remove_name_entry(work->work_group,0x1d);
- remove_name_entry(MSBROWSE ,0x01);
+ /* can only remove master or domain types with this function */
+ remove_type &= ~(SV_TYPE_MASTER_BROWSER|SV_TYPE_DOMAIN_MASTER);
+
+ /* unbecome a master browser; unbecome a domain master, too :-( */
+ if (remove_type & SV_TYPE_MASTER_BROWSER)
+ remove_type |= SV_TYPE_DOMAIN_MASTER;
+
+ new_server_type &= ~remove_type;
+
+ if (!(new_server_type & (SV_TYPE_MASTER_BROWSER|SV_TYPE_DOMAIN_MASTER)))
+ {
+ /* no longer a master browser of any sort */
+
+ work->ServerType |= SV_TYPE_POTENTIAL_BROWSER;
+ work->ElectionCriterion &= ~0x4;
+ work->state = MST_NONE;
+
+ /* announce ourselves as no longer active as a master browser. */
+ announce_server(d, work, work->work_group, myname, 0, 0);
+ remove_name_entry(d,MSBROWSE ,0x01);
+ }
+
+ work->ServerType = new_server_type;
+
+ if (!(work->ServerType & SV_TYPE_DOMAIN_MASTER))
+ {
+ if (work->state == MST_DOMAIN)
+ work->state = MST_BROWSER;
+ remove_name_entry(d,work->work_group,0x1b);
+
+ }
+
+ if (!(work->ServerType & SV_TYPE_DOMAIN_MASTER))
+ {
+ if (work->state >= MST_BROWSER)
+ work->state = MST_NONE;
+ remove_name_entry(d,work->work_group,0x1d);
+ }
}
@@ -234,27 +489,29 @@
lastime = t;
for (d = subnetlist; d; d = d->next)
- {
- struct work_record *work;
- for (work = d->workgrouplist; work; work = work->next)
+ {
+ struct work_record *work;
+ for (work = d->workgrouplist; work; work = work->next)
{
if (work->RunningElection)
- {
- send_election(d,work->work_group, work->ElectionCriterion,
+ {
+ send_election(d,work->work_group, work->ElectionCriterion,
t-StartupTime,myname);
- if (work->ElectionCount++ >= 4)
+ if (work->ElectionCount++ >= 4)
{
/* I won! now what :-) */
DEBUG(2,(">>> Won election on %s %s <<<\n",
work->work_group,inet_ntoa(d->bcast_ip)));
work->RunningElection = False;
+ work->state = MST_NONE;
+
become_master(d, work);
}
- }
+ }
}
- }
+ }
}
@@ -292,7 +549,7 @@
{
struct dgram_packet *dgram = &p->packet.dgram;
struct in_addr ip = dgram->header.source_ip;
- struct subnet_record *d = find_domain(ip);
+ struct subnet_record *d = find_subnet(ip);
int version = CVAL(buf,0);
uint32 criterion = IVAL(buf,1);
int timeup = IVAL(buf,5)/1000;
@@ -320,6 +577,7 @@
{
work->needelection = True;
work->ElectionCount=0;
+ work->state = MST_NONE;
}
}
else
@@ -334,9 +592,10 @@
/* if we are the master then remove our masterly names */
if (AM_MASTER(work))
- {
- become_nonmaster(d, work);
- }
+ {
+ become_nonmaster(d, work,
+ SV_TYPE_MASTER_BROWSER|SV_TYPE_DOMAIN_MASTER);
+ }
}
}
}
@@ -346,6 +605,11 @@
/****************************************************************************
checks whether a browser election is to be run on any workgroup
+
+ this function really ought to return the time between election
+ packets (which depends on whether samba intends to be a domain
+ master or a master browser) in milliseconds.
+
***************************************************************************/
BOOL check_elections(void)
{
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/nameelect.doc samba-1.9.16alpha11/source/nameelect.doc
--- samba-1.9.16alpha10/source/nameelect.doc Thu Jan 1 10:00:00 1970
+++ samba-1.9.16alpha11/source/nameelect.doc Thu Jul 11 04:48:26 1996
@@ -0,0 +1,214 @@
+
+the module nameelect.c deals with initiating, winning, losing
+browsing elections, and checking if browsers are still around,
+and the consequences of getting involved in all this.
+
+an election packet can be received at any time, which will initiate
+an election. samba can also detect that there is no longer a
+master browser and will initiate an election.
+
+there is one way to become a master browser, but there are two
+ways to un-become a master browser. if you lose an election, you
+must stop being a master browser. if you fail to register your
+unique special browser names (either on your local subnet or with
+the WINS server) then you must stop being a master browser.
+
+this is a double fail-safe mechanism to ensure that there is only
+one master browser per workgroup per subnet (and one primary domain
+controller - domain master browser - per domain (workgroup) per
+wide area network).
+
+(a wide area network is created when one or more servers on a
+broadcast-isolated subnet point to the same WINS server).
+
+
+/*************************************************************************
+ check_elections()
+ *************************************************************************/
+
+this function returns True if samba is in the process of running an
+election on any of its interfaces. a better version of this function
+should return the time-out period in between election packets, in
+milliseconds.
+
+
+/*************************************************************************
+ process_election()
+ *************************************************************************/
+
+this function is responsible for dealing with the receipt of an election
+browse MAILSLOT packet.
+
+if samba is running an election, it checks the criteria in the packet
+received using win_election() to see if it has lost the election or if
+it should join in the election.
+
+if it loses the election, then it becomes a non-master.
+
+
+/*************************************************************************
+ win_election()
+ *************************************************************************/
+
+this function returns True if samba has won an election. the criteria
+in order of precedence are:
+
+the election version; the election criteria; the time since samba was
+started; and as a last resort, a name comparison is used.
+
+
+/*************************************************************************
+ run_elections()
+ *************************************************************************/
+
+this function is responsible for sending out election packets if
+samba is running in an election. once the fourth packet is sent
+out, it is assumed that we have won, and samba initiates becoming
+a master browser.
+
+(it looks like samba sends out an extra packet just to be sure...)
+
+
+/*************************************************************************
+ become_nonmaster()
+ *************************************************************************/
+
+this function is responsible for down-grading samba's status from
+either domain master to master browser or nothing, or master browser
+to nothing, depending on its current status.
+
+samba can become a non-master in three ways: by losing an election -
+see process_election(); by having one of its special browser names
+de-registered - see name_unregister_work(); by receiving and
+processing a browser reset packet - see process_reset_browser().
+
+when samba stops being a domain master, it must release its unique
+0x1b name. when samba stops being a master browser, it must release
+its unique 0x1d name.
+
+becoming non-master is done on a per-subnet basis.
+
+
+/*************************************************************************
+ become_master()
+ *************************************************************************/
+
+this function is responsible for slowly turning samba into a
+master browser or a domain master (primary domain controller).
+
+
+this is done in stages. note that this could take a while,
+particularly on a broadcast subnet, as we have to wait for
+the implicit registration of each name to be accepted.
+
+as each name is successfully registered, become_master() is
+called again via name_register_work(), in order to initiate
+the next stage (see dead_netbios_entry() - deals with implicit
+name registration and response_name_reg() - deals with explicit
+registration with a WINS server).
+
+stage 1: was MST_NONE - go to MST_NONE and register ^1^2__MSBROWSE__^2^1.
+stage 2: was MST_WON - go to MST_MSB and register WORKGROUP(0x1d)
+stage 3: was MST_MSB - go to MST_BROWSER and register WORKGROUP(0x1b)
+stage 4: was MST_BROWSER - go to MST_DOMAIN (do not pass GO, do not...)
+
+note that this code still does not cope with the distinction
+between different types of nodes, particularly between M and P
+nodes (see rfc1001.txt). that will be developed later.
+
+
+/*************************************************************************
+ name_register_work()
+ *************************************************************************/
+
+this function is called when a NetBIOS name is successfully
+registered. it will add the registered name into samba's NetBIOS
+records.
+
+it has the additional responsibility that when samba is becoming
+a master browser, it must initiate the next stage in the progress
+towards becoming a master browser.
+
+implicit name registration is done through dead_netbios_entry()
+by time-out. explicit name registration is done through
+response_name_reg() with a WINS server.
+
+
+/*************************************************************************
+ name_unregister_work()
+ *************************************************************************/
+
+this function is called when there is an objection to a NetBIOS
+name being registered. this will always be done through a negative
+response to a name registration, whether it be by a host that
+already owns the unique name being registered on a subnet, or
+by a WINS server.
+
+the name being objected to must be removed from samba's records.
+
+it has the additional responsibility of checking whether samba is
+currently a master browser or not, and if so it should initiate
+becoming a non-master.
+
+
+
+/*************************************************************************
+ send_election()
+ *************************************************************************/
+
+this function is responsible for sending a browse mailslot
+datagram election packet (of type ANN_Election). it constructs
+the packet with all the relevant info needed to participate:
+election version; election criteria; time since startup and
+our name.
+
+this function can be used to ensure that initiate but lose an
+election by specifying a criteria and time up of zero. this
+is necessary if we are a master browser and we are about to
+go down (politely!) - see nmbd.c:sig_term().
+
+
+/*************************************************************************
+ browser_gone()
+ *************************************************************************/
+
+this function is responsible for dealing with the instance when
+the master browser we thought was present on a subnet is no longer
+responding.
+
+if it is samba's workgroup, and it's a local interface, samba
+detects that it can participate in an election on that interface
+and potentially become a master browser or domain master.
+
+if it's a local subnet and not one of samba's workgroups, then
+samba will force an election (which it is not obliged to do).
+remove_workgroup() will be expected to remove all references
+to this workgroup and the servers in it from the database.
+
+if it's a remote subnet and not one of samba's workgroups then
+no election is forced, and remove_workgroup() will be expected
+to remove all server entries from this workgroup _except_ those
+added from the lmhosts file. if there are entries added from
+the lmhosts file, then the workgroup entry will remain,
+otherwise it too will be removed.
+
+
+/*************************************************************************
+ check_master_browser()
+ *************************************************************************/
+
+this function is responsible for periodically checking whether
+master browsers that samba expects to be alive are alive. this
+is done every CHECK_TIME_MST_BROWSE minutes.
+
+for every workgroup record for which samba is not a master browser,
+on both local and remote interfaces, samba will initiate a
+broadcast query for a master browser on that subnet.
+
+(browser_gone() will be called to deal with the case where no
+response is received to the NAME_QUERY_MST_CHK initiated here.
+no action is required when a response _is_ received, however:
+see nameservresp.c:response_process() and dead_netbios_entry()
+for details)
+
+
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/namelogon.c samba-1.9.16alpha11/source/namelogon.c
--- samba-1.9.16alpha10/source/namelogon.c Thu Jan 1 10:00:00 1970
+++ samba-1.9.16alpha11/source/namelogon.c Wed Jul 3 01:31:12 1996
@@ -0,0 +1,119 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1995
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Revision History:
+
+ 14 jan 96: lkcl@pires.co.uk
+ added multiple workgroup domain master support
+
+*/
+
+#include "includes.h"
+
+extern int ClientDGRAM;
+
+#define TEST_CODE /* want to debug unknown browse packets */
+
+extern int DEBUGLEVEL;
+
+extern pstring myname;
+
+
+/****************************************************************************
+ process a domain logon packet
+ **************************************************************************/
+void process_logon_packet(struct packet_struct *p,char *buf,int len)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ struct in_addr ip = dgram->header.source_ip;
+ struct subnet_record *d = find_subnet(ip);
+ char *logname,*q;
+ char *reply_name;
+ BOOL add_slashes = False;
+ pstring outbuf;
+ int code,reply_code;
+ struct work_record *work;
+
+ if (!d) return;
+
+ if (!(work = find_workgroupstruct(d,dgram->dest_name.name, False)))
+ return;
+
+ if (!lp_domain_logons()) {
+ DEBUG(3,("No domain logons\n"));
+ return;
+ }
+ if (!listening_name(work, &dgram->dest_name))
+ {
+ DEBUG(4,("Not listening to that domain\n"));
+ return;
+ }
+
+ code = SVAL(buf,0);
+ switch (code) {
+ case 0:
+ {
+ char *machine = buf+2;
+ char *user = skip_string(machine,1);
+ logname = skip_string(user,1);
+ reply_code = 6;
+ reply_name = myname;
+ add_slashes = True;
+ DEBUG(3,("Domain login request from %s(%s) user=%s\n",
+ machine,inet_ntoa(p->ip),user));
+ }
+ break;
+ case 7:
+ {
+ char *machine = buf+2;
+ logname = skip_string(machine,1);
+ reply_code = 7;
+ reply_name = lp_domain_controller();
+ if (!*reply_name) {
+ DEBUG(3,("No domain controller configured\n"));
+ return;
+ }
+ DEBUG(3,("GETDC request from %s(%s)\n",
+ machine,inet_ntoa(p->ip)));
+ }
+ break;
+ default:
+ DEBUG(3,("Unknown domain request %d\n",code));
+ return;
+ }
+
+ bzero(outbuf,sizeof(outbuf));
+ q = outbuf;
+ SSVAL(q,0,reply_code);
+ q += 2;
+ if (add_slashes) {
+ strcpy(q,"\\\\");
+ q += 2;
+ }
+ StrnCpy(q,reply_name,16);
+ strupper(q);
+ q = skip_string(q,1);
+ SSVAL(q,0,0xFFFF);
+ q += 2;
+
+ send_mailslot_reply(logname,ClientDGRAM,outbuf,PTR_DIFF(q,outbuf),
+ myname,&dgram->source_name.name[0],0x20,0,p->ip,
+ *iface_ip(p->ip));
+}
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/namelogon.doc samba-1.9.16alpha11/source/namelogon.doc
--- samba-1.9.16alpha10/source/namelogon.doc Thu Jan 1 10:00:00 1970
+++ samba-1.9.16alpha11/source/namelogon.doc Sun Jul 7 22:35:55 1996
@@ -0,0 +1,9 @@
+this module deals with the first stage of domain logons. there is much
+more work to be done on this: it's all totally undocumented.
+
+
+/*************************************************************************
+ process_logon_packet()
+ *************************************************************************/
+
+a function that processes logon packets (the most helpful comment yet :-).
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/namepacket.c samba-1.9.16alpha11/source/namepacket.c
--- samba-1.9.16alpha10/source/namepacket.c Thu Jan 1 10:00:00 1970
+++ samba-1.9.16alpha11/source/namepacket.c Thu Jul 18 20:53:15 1996
@@ -0,0 +1,581 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1995
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Revision History:
+
+ 14 jan 96: lkcl@pires.co.uk
+ added multiple workgroup domain master support
+
+*/
+
+#include "includes.h"
+
+extern int ClientNMB;
+extern int ClientDGRAM;
+
+extern int DEBUGLEVEL;
+
+extern int num_response_packets;
+
+BOOL CanRecurse = True;
+extern pstring scope;
+extern struct in_addr ipgrp;
+
+static uint16 name_trn_id=0;
+
+
+/***************************************************************************
+ updates the unique transaction identifier
+ **************************************************************************/
+void debug_browse_data(char *outbuf, int len)
+{
+ int i,j;
+ for (i = 0; i < len; i+= 16)
+ {
+ DEBUG(4, ("%3x char ", i));
+
+ for (j = 0; j < 16; j++)
+ {
+ unsigned char x = outbuf[i+j];
+ if (x < 32 || x > 127) x = '.';
+
+ if (i+j >= len) break;
+ DEBUG(4, ("%c", x));
+ }
+
+ DEBUG(4, (" hex ", i));
+
+ for (j = 0; j < 16; j++)
+ {
+ if (i+j >= len) break;
+ DEBUG(4, (" %02x", outbuf[i+j]));
+ }
+
+ DEBUG(4, ("\n"));
+ }
+
+}
+
+
+/***************************************************************************
+ updates the unique transaction identifier
+ **************************************************************************/
+static void update_name_trn_id(void)
+{
+ if (!name_trn_id)
+ {
+ name_trn_id = (time(NULL)%(unsigned)0x7FFF) + (getpid()%(unsigned)100);
+ }
+ name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
+}
+
+
+/****************************************************************************
+ initiate a netbios packet
+ ****************************************************************************/
+void initiate_netbios_packet(uint16 *id,
+ int fd,int quest_type,char *name,int name_type,
+ int nb_flags,BOOL bcast,BOOL recurse,
+ struct in_addr to_ip)
+{
+ struct packet_struct p;
+ struct nmb_packet *nmb = &p.packet.nmb;
+ struct res_rec additional_rec;
+ char *packet_type = "unknown";
+ int opcode = -1;
+
+ if (!id) return;
+
+ if (quest_type == NMB_STATUS) { packet_type = "nmb_status"; opcode = 0; }
+ if (quest_type == NMB_QUERY ) { packet_type = "nmb_query"; opcode = 0; }
+ if (quest_type == NMB_REG ) { packet_type = "nmb_reg"; opcode = 5; }
+ if (quest_type == NMB_REL ) { packet_type = "nmb_rel"; opcode = 6; }
+
+ DEBUG(4,("initiating netbios packet: %s %s(%x) (bcast=%s) %s\n",
+ packet_type, name, name_type, BOOLSTR(bcast), inet_ntoa(to_ip)));
+
+ if (opcode == -1) return;
+
+ bzero((char *)&p,sizeof(p));
+
+ if (*id == 0xffff) {
+ update_name_trn_id();
+ *id = name_trn_id; /* allow resending with same id */
+ }
+
+ nmb->header.name_trn_id = *id;
+ nmb->header.opcode = opcode;
+ nmb->header.response = False;
+
+ nmb->header.nm_flags.bcast = bcast;
+ nmb->header.nm_flags.recursion_available = CanRecurse;
+ nmb->header.nm_flags.recursion_desired = recurse;
+ nmb->header.nm_flags.trunc = False;
+ nmb->header.nm_flags.authoritative = False;
+
+ nmb->header.rcode = 0;
+ nmb->header.qdcount = 1;
+ nmb->header.ancount = 0;
+ nmb->header.nscount = 0;
+ nmb->header.arcount = (quest_type==NMB_REG || quest_type==NMB_REL) ? 1 : 0;
+
+ make_nmb_name(&nmb->question.question_name,name,name_type,scope);
+
+ nmb->question.question_type = quest_type;
+ nmb->question.question_class = 0x1;
+
+ if (quest_type == NMB_REG || quest_type == NMB_REL)
+ {
+ nmb->additional = &additional_rec;
+ bzero((char *)nmb->additional,sizeof(*nmb->additional));
+
+ nmb->additional->rr_name = nmb->question.question_name;
+ nmb->additional->rr_type = nmb->question.question_type;
+ nmb->additional->rr_class = nmb->question.question_class;
+
+ nmb->additional->ttl = quest_type == NMB_REG ? lp_max_ttl() : 0;
+ nmb->additional->rdlength = 6;
+ nmb->additional->rdata[0] = nb_flags;
+ putip(&nmb->additional->rdata[2],(char *)iface_ip(to_ip));
+ }
+
+ p.ip = to_ip;
+ p.port = NMB_PORT;
+ p.fd = fd;
+ p.timestamp = time(NULL);
+ p.packet_type = NMB_PACKET;
+
+ if (!send_packet(&p)) *id = 0xffff;
+
+ return;
+}
+
+
+/****************************************************************************
+ reply to a netbios name packet
+ ****************************************************************************/
+void reply_netbios_packet(struct packet_struct *p1,int trn_id,
+ int rcode, int rcv_code, int opcode, BOOL recurse,
+ struct nmb_name *rr_name,int rr_type,int rr_class,int ttl,
+ char *data,int len)
+{
+ struct packet_struct p;
+ struct nmb_packet *nmb = &p.packet.nmb;
+ struct res_rec answers;
+ char *packet_type = "unknown";
+ BOOL recursion_desired = False;
+
+ p = *p1;
+
+ switch (rcv_code)
+ {
+ case NMB_STATUS:
+ {
+ packet_type = "nmb_status";
+ recursion_desired = True;
+ break;
+ }
+ case NMB_QUERY:
+ {
+ packet_type = "nmb_query";
+ recursion_desired = True;
+ break;
+ }
+ case NMB_REG:
+ {
+ packet_type = "nmb_reg";
+ recursion_desired = True;
+ break;
+ }
+ case NMB_REL:
+ {
+ packet_type = "nmb_rel";
+ recursion_desired = False;
+ break;
+ }
+ case NMB_WAIT_ACK:
+ {
+ packet_type = "nmb_wack";
+ recursion_desired = False;
+ break;
+ }
+ default:
+ {
+ DEBUG(1,("replying netbios packet: %s %s\n",
+ packet_type, namestr(rr_name), inet_ntoa(p.ip)));
+
+ return;
+ }
+ }
+
+ DEBUG(4,("replying netbios packet: %s %s\n",
+ packet_type, namestr(rr_name), inet_ntoa(p.ip)));
+
+ nmb->header.name_trn_id = trn_id;
+ nmb->header.opcode = opcode;
+ nmb->header.response = True;
+ nmb->header.nm_flags.bcast = False;
+ nmb->header.nm_flags.recursion_available = recurse;
+ nmb->header.nm_flags.recursion_desired = recursion_desired;
+ nmb->header.nm_flags.trunc = False;
+ nmb->header.nm_flags.authoritative = True;
+
+ nmb->header.qdcount = 0;
+ nmb->header.ancount = 1;
+ nmb->header.nscount = 0;
+ nmb->header.arcount = 0;
+ nmb->header.rcode = 0;
+
+ bzero((char*)&nmb->question,sizeof(nmb->question));
+
+ nmb->answers = &answers;
+ bzero((char*)nmb->answers,sizeof(*nmb->answers));
+
+ nmb->answers->rr_name = *rr_name;
+ nmb->answers->rr_type = rr_type;
+ nmb->answers->rr_class = rr_class;
+ nmb->answers->ttl = ttl;
+
+ if (data && len)
+ {
+ nmb->answers->rdlength = len;
+ memcpy(nmb->answers->rdata, data, len);
+ }
+
+ p.packet_type = NMB_PACKET;
+
+ debug_nmb_packet(&p);
+
+ send_packet(&p);
+}
+
+
+/*******************************************************************
+ the global packet linked-list. incoming entries are added to the
+ end of this list. it is supposed to remain fairly short so we
+ won't bother with an end pointer.
+ ******************************************************************/
+static struct packet_struct *packet_queue = NULL;
+
+/*******************************************************************
+ queue a packet into the packet queue
+ ******************************************************************/
+void queue_packet(struct packet_struct *packet)
+{
+ struct packet_struct *p;
+
+ if (!packet_queue) {
+ packet->prev = NULL;
+ packet->next = NULL;
+ packet_queue = packet;
+ return;
+ }
+
+ /* find the bottom */
+ for (p=packet_queue;p->next;p=p->next) ;
+
+ p->next = packet;
+ packet->next = NULL;
+ packet->prev = p;
+}
+
+
+/****************************************************************************
+ process udp 138 datagrams
+ ****************************************************************************/
+static void process_dgram(struct packet_struct *p)
+{
+ char *buf;
+ char *buf2;
+ int len;
+ struct dgram_packet *dgram = &p->packet.dgram;
+
+ if (dgram->header.msg_type != 0x10 &&
+ dgram->header.msg_type != 0x11 &&
+ dgram->header.msg_type != 0x12) {
+ /* don't process error packets etc yet */
+ return;
+ }
+
+ buf = &dgram->data[0];
+ buf -= 4; /* XXXX for the pseudo tcp length -
+ someday I need to get rid of this */
+
+ if (CVAL(buf,smb_com) != SMBtrans) return;
+
+ len = SVAL(buf,smb_vwv11);
+ buf2 = smb_base(buf) + SVAL(buf,smb_vwv12);
+
+ DEBUG(4,("datagram from %s to %s for %s of type %d len=%d\n",
+ namestr(&dgram->source_name),namestr(&dgram->dest_name),
+ smb_buf(buf),CVAL(buf2,0),len));
+
+
+ if (len <= 0) return;
+
+ /* datagram packet received for the browser mailslot */
+ if (strequal(smb_buf(buf),BROWSE_MAILSLOT)) {
+ process_browse_packet(p,buf2,len);
+ return;
+ }
+
+ /* datagram packet received for the domain log on mailslot */
+ if (strequal(smb_buf(buf),NET_LOGON_MAILSLOT)) {
+ process_logon_packet(p,buf2,len);
+ return;
+ }
+}
+
+/****************************************************************************
+ process a nmb packet
+ ****************************************************************************/
+static void process_nmb(struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+
+ debug_nmb_packet(p);
+
+ switch (nmb->header.opcode)
+ {
+ case 8: /* what is this?? */
+ case NMB_REG:
+ case NMB_REG_REFRESH:
+ {
+ if (nmb->header.qdcount==0 || nmb->header.arcount==0) break;
+ if (nmb->header.response)
+ response_netbios_packet(p); /* response to registration dealt with here */
+ else
+ reply_name_reg(p);
+ break;
+ }
+
+ case 0:
+ {
+ if (nmb->header.response)
+ {
+ switch (nmb->question.question_type)
+ {
+ case 0x0:
+ {
+ response_netbios_packet(p);
+ break;
+ }
+ }
+ return;
+ }
+ else if (nmb->header.qdcount>0)
+ {
+ switch (nmb->question.question_type)
+ {
+ case NMB_QUERY:
+ {
+ reply_name_query(p);
+ break;
+ }
+ case NMB_STATUS:
+ {
+ reply_name_status(p);
+ break;
+ }
+ }
+ return;
+ }
+ break;
+ }
+
+ case NMB_REL:
+ {
+ if (nmb->header.qdcount==0 || nmb->header.arcount==0)
+ {
+ DEBUG(2,("netbios release packet rejected\n"));
+ break;
+ }
+
+ if (nmb->header.response)
+ response_netbios_packet(p); /* response to reply dealt with in here */
+ else
+ reply_name_release(p);
+ break;
+ }
+ }
+}
+
+
+/*******************************************************************
+ run elements off the packet queue till its empty
+ ******************************************************************/
+void run_packet_queue()
+{
+ struct packet_struct *p;
+
+ while ((p=packet_queue))
+ {
+ switch (p->packet_type)
+ {
+ case NMB_PACKET:
+ process_nmb(p);
+ break;
+
+ case DGRAM_PACKET:
+ process_dgram(p);
+ break;
+ }
+
+ packet_queue = packet_queue->next;
+ if (packet_queue) packet_queue->prev = NULL;
+ free_packet(p);
+ }
+}
+
+/****************************************************************************
+ listens for NMB or DGRAM packets, and queues them
+ ***************************************************************************/
+void listen_for_packets(BOOL run_election)
+{
+ fd_set fds;
+ int selrtn;
+ struct timeval timeout;
+
+ FD_ZERO(&fds);
+ FD_SET(ClientNMB,&fds);
+ FD_SET(ClientDGRAM,&fds);
+
+ /* during elections and when expecting a netbios response packet we need
+ to send election packets at one second intervals.
+ XXXX actually, it needs to be the interval (in ms) between time now and the
+ time we are expecting the next netbios packet */
+
+ timeout.tv_sec = (run_election||num_response_packets) ? 1 : NMBD_SELECT_LOOP;
+ timeout.tv_usec = 0;
+
+ selrtn = sys_select(&fds,&timeout);
+
+ if (FD_ISSET(ClientNMB,&fds))
+ {
+ struct packet_struct *packet = read_packet(ClientNMB, NMB_PACKET);
+ if (packet) {
+#if 1
+ if (ismyip(packet->ip) &&
+ (packet->port == NMB_PORT || packet->port == DGRAM_PORT)) {
+ DEBUG(5,("discarding own packet from %s:%d\n",
+ inet_ntoa(packet->ip),packet->port));
+ free_packet(packet);
+ } else
+#endif
+ {
+ queue_packet(packet);
+ }
+ }
+ }
+
+ if (FD_ISSET(ClientDGRAM,&fds))
+ {
+ struct packet_struct *packet = read_packet(ClientDGRAM, DGRAM_PACKET);
+ if (packet) {
+#if 1
+ if (ismyip(packet->ip) &&
+ (packet->port == NMB_PORT || packet->port == DGRAM_PORT)) {
+ DEBUG(5,("discarding own packet from %s:%d\n",
+ inet_ntoa(packet->ip),packet->port));
+ free_packet(packet);
+ } else
+#endif
+ {
+ queue_packet(packet);
+ }
+ }
+ }
+}
+
+
+
+/****************************************************************************
+ construct and send a netbios DGRAM
+
+ Note that this currently sends all answers to port 138. thats the
+ wrong things to do! I should send to the requestors port. XXX
+ **************************************************************************/
+BOOL send_mailslot_reply(char *mailslot,int fd,char *buf,int len,char *srcname,
+ char *dstname,int src_type,int dest_type,
+ struct in_addr dest_ip,struct in_addr src_ip)
+{
+ struct packet_struct p;
+ struct dgram_packet *dgram = &p.packet.dgram;
+ struct in_addr wins_ip = ipgrp;
+ char *ptr,*p2;
+ char tmp[4];
+
+ /* ha ha. no. do NOT send packets to 255.255.255.255: it's a pseudo address */
+ if (ip_equal(wins_ip, dest_ip)) return False;
+
+ bzero((char *)&p,sizeof(p));
+
+ update_name_trn_id();
+
+ dgram->header.msg_type = 0x11; /* DIRECT GROUP DATAGRAM */
+ dgram->header.flags.node_type = M_NODE;
+ dgram->header.flags.first = True;
+ dgram->header.flags.more = False;
+ dgram->header.dgm_id = name_trn_id;
+ dgram->header.source_ip = src_ip;
+ dgram->header.source_port = DGRAM_PORT;
+ dgram->header.dgm_length = 0; /* let build_dgram() handle this */
+ dgram->header.packet_offset = 0;
+
+ make_nmb_name(&dgram->source_name,srcname,src_type,scope);
+ make_nmb_name(&dgram->dest_name,dstname,dest_type,scope);
+
+ ptr = &dgram->data[0];
+
+ /* now setup the smb part */
+ ptr -= 4; /* XXX ugliness because of handling of tcp SMB length */
+ memcpy(tmp,ptr,4);
+ set_message(ptr,17,17 + len,True);
+ memcpy(ptr,tmp,4);
+
+ CVAL(ptr,smb_com) = SMBtrans;
+ SSVAL(ptr,smb_vwv1,len);
+ SSVAL(ptr,smb_vwv11,len);
+ SSVAL(ptr,smb_vwv12,70 + strlen(mailslot));
+ SSVAL(ptr,smb_vwv13,3);
+ SSVAL(ptr,smb_vwv14,1);
+ SSVAL(ptr,smb_vwv15,1);
+ SSVAL(ptr,smb_vwv16,2);
+ p2 = smb_buf(ptr);
+ strcpy(p2,mailslot);
+ p2 = skip_string(p2,1);
+
+ memcpy(p2,buf,len);
+ p2 += len;
+
+ dgram->datasize = PTR_DIFF(p2,ptr+4); /* +4 for tcp length */
+
+ p.ip = dest_ip;
+ p.port = DGRAM_PORT;
+ p.fd = ClientDGRAM;
+ p.timestamp = time(NULL);
+ p.packet_type = DGRAM_PACKET;
+
+ DEBUG(4,("send mailslot %s from %s %s", mailslot,
+ inet_ntoa(src_ip),namestr(&dgram->source_name)));
+ DEBUG(4,("to %s %s\n", inet_ntoa(dest_ip),namestr(&dgram->dest_name)));
+
+ return(send_packet(&p));
+}
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/namepacket.doc samba-1.9.16alpha11/source/namepacket.doc
--- samba-1.9.16alpha10/source/namepacket.doc Thu Jan 1 10:00:00 1970
+++ samba-1.9.16alpha11/source/namepacket.doc Sun Jul 7 22:35:55 1996
@@ -0,0 +1,106 @@
+this module deals with packets: sending, receiving, queueing
+and some basic interpretation (e.g it excludes datagram
+error packets at the moment).
+
+the packet queueing mechanism was originally introduced when
+samba dealt with responses by sending a packet, receiving
+packets and queueing all packets that didn't match up with
+the response expected. this is fine in a single-thread
+environment, but samba now deals with response packets by
+queueing the responses. to some extent, therefore, this
+queue_packet mechanism is redundant.
+
+
+/*************************************************************************
+ send_mailslot_reply()
+ *************************************************************************/
+
+this function is responsible for sending a MAILSLOT packet.
+
+it will _not_ send packets to the pseudo WINS subnet's address of
+255.255.255.255: this would be disastrous.
+
+each packet sent out has a unique transaction identifier. this is done
+so that responses can be matched later with the original purpose for
+the packet being sent out in the first place.
+
+
+/*************************************************************************
+ listen_for_packets()
+ *************************************************************************/
+
+this function is responsible for reading NMB and DGRAM packets, and then
+queueing them. it will normally time-out for NMBD_SELECT_LOOP seconds, but
+if there is an election currently running or we are expecting a response
+then this time is reduced to 1 second.
+
+note: the time-out period needs refining to the millisecond level.
+
+
+/*************************************************************************
+ queue_packet()
+ *************************************************************************/
+
+this function is responsible for queueing any NMB and DGRAM packets passed
+to it. these packets will be removed from the queue in run_packet_queue().
+
+
+/*************************************************************************
+ run_packet_queue()
+ *************************************************************************/
+
+this function is responsible for taking a packet off the queue,
+identifying whether it is an NMB or a DGRAM packet, processing
+it accordingly and deleting it. this process continues until
+there are no more packets on the queue.
+
+
+/*************************************************************************
+ process_nmb()
+ *************************************************************************/
+
+this function receives a packet identified as a netbios packet.
+it further identifies whether it is a response or a query packet.
+by identifying the type of packet (name registration, query etc)
+process_nmb() will call the appropriate function to deal with the
+type of packet received.
+
+
+/*************************************************************************
+ process_dgram()
+ *************************************************************************/
+
+this function is responsible for identifying whether the datagram
+packet received is a browser packet or a domain logon packet. it
+also does some filtering of certain types of packets (e.g it
+filters out error packets).
+
+
+/*************************************************************************
+ reply_netbios_packet()
+ *************************************************************************/
+
+this function is responsible for sending a reply to another NetBIOS
+packet from another host. it can be used to send a reply to a name
+registration, name release, name query or name status request.
+
+the reply can be either a positive or a negative one.
+
+
+/*************************************************************************
+ initiate_netbios_packet()
+ *************************************************************************/
+
+this function is responsible for construction a netbios packet and sending
+it. if the packet has not had a unique transaction id allocated to it,
+then initiate_netbios_packet() will give it one.
+
+
+/*************************************************************************
+ update_name_trn_id()
+ *************************************************************************/
+
+this function is responsible for allocating unique transaction identifiers
+for each new packet sent on the network.
+
+
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/namequery.c samba-1.9.16alpha11/source/namequery.c
--- samba-1.9.16alpha10/source/namequery.c Tue Jun 4 16:41:15 1996
+++ samba-1.9.16alpha11/source/namequery.c Thu Jul 18 20:53:15 1996
@@ -173,6 +173,8 @@
continue;
}
+ debug_nmb_packet(p2);
+
_interpret_node_status(&nmb2->answers->rdata[0], master,rname);
free_packet(p2);
return(True);
@@ -266,6 +268,8 @@
continue;
}
+ debug_nmb_packet(p2);
+
if (nmb2->header.opcode != 0 ||
nmb2->header.nm_flags.bcast ||
nmb2->header.rcode ||
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/namequery.doc samba-1.9.16alpha11/source/namequery.doc
--- samba-1.9.16alpha10/source/namequery.doc Thu Jan 1 10:00:00 1970
+++ samba-1.9.16alpha11/source/namequery.doc Sun Jul 7 22:35:56 1996
@@ -0,0 +1,56 @@
+this module contains non-threaded versions of name status and name
+query functions. if a multi-threaded nmbd was to be written, these
+functions would be the starting point.
+
+at the moment, the expected response queueing system is used to
+replace these functions without needing to multi-thread nmbd.
+
+these functions are used in smbclient and nmblookup at present to
+avoid having the vast quantities of complex and unused code needed
+to support even a simple name query (or providing stubs for the
+unused side of these functions).
+
+there is a down-side to these functions, which is all microsoft's
+fault. microsoft machines always always reply to queries on the
+priveleged ports, rather than following the usual tcp/ip mechanism
+of replying on the client's port (the exception to this i am led
+to believe is windows nt 3.50).
+
+as a result of this, in order to receive a response to a name
+query from a microsoft machine, we must be able to listen on
+the priveleged netbios name server ports. this is simply not
+possible with some versions of unix, unless you have root access.
+
+it is also not possible if you run smbclient or nmblookup on an
+interface that already has been claimed by the netbios name server
+daemon nmbd.
+
+all in all, i wish that microsoft would fix this.
+
+a solution does exist: nmbd _does_ actually reply on the client's
+port, so if smbclient and nmblookup were to use nmbd as a proxy
+forwarder of queries (or to use samba's WINS capabilities) then
+a query could be made without needing access to the priveleged
+ports. in order to do this properly, samba must implement secured
+netbios name server functionality (see rfc1001.txt 15.1.6).
+
+
+/*************************************************************************
+ name_query()
+ *************************************************************************/
+
+
+
+/*************************************************************************
+ name_status()
+ *************************************************************************/
+
+
+
+/*************************************************************************
+ _interpret_node_status()
+ *************************************************************************/
+
+
+this is a older version of interpret_node_status().
+
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/nameresp.c samba-1.9.16alpha11/source/nameresp.c
--- samba-1.9.16alpha10/source/nameresp.c Mon Jun 10 15:18:56 1996
+++ samba-1.9.16alpha11/source/nameresp.c Thu Jul 18 20:53:15 1996
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
NBT netbios library routines
- Copyright (C) Andrew Tridgell 1994-1995
+ Copyright (C) Andrew Tridgell 1994-1996
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,6 +18,8 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ Module name: nameresp.c
+
*/
#include "includes.h"
@@ -25,214 +27,192 @@
extern int ClientNMB;
extern int ClientDGRAM;
-/* this is our initiated name query response database */
-struct name_response_record *nameresponselist = NULL;
+extern struct subnet_record *subnetlist;
extern int DEBUGLEVEL;
-static uint16 name_trn_id=0;
-BOOL CanRecurse = True;
extern pstring scope;
-extern pstring myname;
extern struct in_addr ipzero;
+extern struct in_addr ipgrp;
/***************************************************************************
- add an initated name query into the list
+ deals with an entry before it dies
**************************************************************************/
-extern void add_response_record(struct name_response_record *n)
+static void dead_netbios_entry(struct subnet_record *d,
+ struct response_record *n)
{
- struct name_response_record *n2;
+ DEBUG(3,("Removing dead netbios entry for %s %s (num_msgs=%d)\n",
+ inet_ntoa(n->send_ip), namestr(&n->name), n->num_msgs));
- if (!nameresponselist)
- {
- nameresponselist = n;
- n->prev = NULL;
- n->next = NULL;
- return;
+ debug_state_type(n->state);
+
+ switch (n->state)
+ {
+ case NAME_QUERY_CONFIRM:
+ {
+ if (!lp_wins_support()) return; /* only if we're a WINS server */
+
+ if (n->num_msgs == 0)
+ {
+ /* oops. name query had no response. check that the name is
+ unique and then remove it from our WINS database */
+
+ /* IMPORTANT: see query_refresh_names() */
+
+ if ((!NAME_GROUP(n->nb_flags)))
+ {
+ struct subnet_record *d1 = find_subnet(ipgrp);
+ if (d1)
+ {
+ /* remove the name that had been registered with us,
+ and we're now getting no response when challenging.
+ see rfc1001.txt 15.5.2
+ */
+ remove_netbios_name(d1, n->name.name, n->name.name_type,
+ REGISTER, n->send_ip);
+ }
+ }
+ }
+ break;
}
-
- for (n2 = nameresponselist; n2->next; n2 = n2->next) ;
-
- n2->next = n;
- n->next = NULL;
- n->prev = n2;
-}
+ case NAME_QUERY_MST_CHK:
+ {
+ /* if no response received, the master browser must have gone
+ down on that subnet, without telling anyone. */
-/*******************************************************************
- remove old name response entries
- ******************************************************************/
-void expire_netbios_response_entries(time_t t)
-{
- struct name_response_record *n;
- struct name_response_record *nextn;
+ /* IMPORTANT: see response_netbios_packet() */
- for (n = nameresponselist; n; n = nextn)
- {
- if (n->start_time < t)
+ if (n->num_msgs == 0)
+ browser_gone(n->name.name, n->send_ip);
+ break;
+ }
+
+ case NAME_RELEASE:
{
- DEBUG(3,("Removing dead name query for %s %s (num_msgs=%d)\n",
- inet_ntoa(n->to_ip), namestr(&n->name), n->num_msgs));
+ /* if no response received, it must be OK for us to release the
+ name. nobody objected (including a potentially dead or deaf
+ WINS server) */
- if (n->cmd_type == CHECK_MASTER)
- {
- /* if no response received, the master browser must have gone */
- if (n->num_msgs == 0)
- browser_gone(n->name.name, n->to_ip);
- }
-
- nextn = n->next;
-
- if (n->prev) n->prev->next = n->next;
- if (n->next) n->next->prev = n->prev;
-
- if (nameresponselist == n) nameresponselist = n->next;
-
- free(n);
+ /* IMPORTANT: see response_name_release() */
+
+ if (ismyip(n->send_ip))
+ {
+ name_unregister_work(d,n->name.name,n->name.name_type);
+ }
+ if (!n->bcast)
+ {
+ DEBUG(0,("WINS server did not respond to name release!\n"));
+ /* XXXX whoops. we have problems. must deal with this */
+ }
+ break;
}
- else
+
+ case NAME_REGISTER_CHALLENGE:
{
- nextn = n->next;
+ /* name challenge: no reply. we can reply to the person that
+ wanted the unique name and tell them that they can have it
+ */
+
+ add_name_respond(d,n->fd,d->myip, n->response_id ,&n->name,
+ n->nb_flags, GET_TTL(0),
+ n->reply_to_ip, False, n->reply_to_ip);
+
+ if (!n->bcast)
+ {
+ DEBUG(1,("WINS server did not respond to name registration!\n"));
+ /* XXXX whoops. we have problems. must deal with this */
+ }
+ break;
}
- }
-}
+ case NAME_REGISTER:
+ {
+ /* if no response received, and we are using a broadcast registration
+ method, it must be OK for us to register the name: nobody objected
+ on that subnet. if we are using a WINS server, then the WINS
+ server must be dead or deaf.
+ */
+ if (n->bcast)
+ {
+ /* broadcast method: implicit acceptance of the name registration
+ by not receiving any objections. */
-/****************************************************************************
- reply to a netbios name packet
- ****************************************************************************/
-void reply_netbios_packet(struct packet_struct *p1,int trn_id,int rcode,
- int opcode,BOOL recurse,struct nmb_name *rr_name,
- int rr_type,int rr_class,int ttl,char *data,int len)
-{
- struct packet_struct p;
- struct nmb_packet *nmb = &p.packet.nmb;
- struct res_rec answers;
- char *packet_type = "unknown";
-
- p = *p1;
+ /* IMPORTANT: see response_name_reg() */
- if (rr_type == NMB_STATUS) packet_type = "nmb_status";
- if (rr_type == NMB_QUERY ) packet_type = "nmb_query";
- if (rr_type == NMB_REG ) packet_type = "nmb_reg";
- if (rr_type == NMB_REL ) packet_type = "nmb_rel";
-
- DEBUG(4,("replying netbios packet: %s %s\n",
- packet_type, namestr(rr_name), inet_ntoa(p.ip)));
+ name_register_work(d,n->name.name,n->name.name_type,
+ n->nb_flags, n->ttl, n->reply_to_ip, n->bcast);
+ }
+ else
+ {
+ /* received no response. rfc1001.txt states that after retrying,
+ we should assume the WINS server is dead, and fall back to
+ broadcasting (see bits about M nodes: can't find any right
+ now) */
+
+ DEBUG(1,("WINS server did not respond to name registration!\n"));
+ /* XXXX whoops. we have problems. must deal with this */
+ }
+ break;
+ }
- nmb->header.name_trn_id = trn_id;
- nmb->header.opcode = opcode;
- nmb->header.response = True;
- nmb->header.nm_flags.bcast = False;
- nmb->header.nm_flags.recursion_available = recurse;
- nmb->header.nm_flags.recursion_desired = True;
- nmb->header.nm_flags.trunc = False;
- nmb->header.nm_flags.authoritative = True;
-
- nmb->header.qdcount = 0;
- nmb->header.ancount = 1;
- nmb->header.nscount = 0;
- nmb->header.arcount = 0;
- nmb->header.rcode = 0;
-
- bzero((char*)&nmb->question,sizeof(nmb->question));
-
- nmb->answers = &answers;
- bzero((char*)nmb->answers,sizeof(*nmb->answers));
-
- nmb->answers->rr_name = *rr_name;
- nmb->answers->rr_type = rr_type;
- nmb->answers->rr_class = rr_class;
- nmb->answers->ttl = ttl;
-
- if (data && len)
- {
- nmb->answers->rdlength = len;
- memcpy(nmb->answers->rdata, data, len);
- }
-
- p.packet_type = NMB_PACKET;
-
- debug_nmb_packet(&p);
-
- send_packet(&p);
+ default:
+ {
+ /* nothing to do but delete the dead expected-response structure */
+ /* this is normal. */
+ break;
+ }
+ }
}
-/****************************************************************************
- initiate a netbios packet
- ****************************************************************************/
-uint16 initiate_netbios_packet(int fd,int quest_type,char *name,int name_type,
- int nb_flags,BOOL bcast,BOOL recurse,
- struct in_addr to_ip)
-{
- struct packet_struct p;
- struct nmb_packet *nmb = &p.packet.nmb;
- struct res_rec additional_rec;
- char *packet_type = "unknown";
- int opcode = -1;
-
- if (quest_type == NMB_STATUS) { packet_type = "nmb_status"; opcode = 0; }
- if (quest_type == NMB_QUERY ) { packet_type = "nmb_query"; opcode = 0; }
- if (quest_type == NMB_REG ) { packet_type = "nmb_reg"; opcode = 5; }
- if (quest_type == NMB_REL ) { packet_type = "nmb_rel"; opcode = 6; }
-
- DEBUG(4,("initiating netbios packet: %s %s(%x) (bcast=%s) %s\n",
- packet_type, name, name_type, BOOLSTR(bcast), inet_ntoa(to_ip)));
+/*******************************************************************
+ remove old name response entries
- if (opcode == -1) return False;
+ XXXX retry code needs to be added, including a retry wait period and a count
+ see name_query() and name_status() for suggested implementation.
- bzero((char *)&p,sizeof(p));
+ ******************************************************************/
+void expire_netbios_response_entries()
+{
+ struct subnet_record *d;
- if (!name_trn_id) name_trn_id = (time(NULL)%(unsigned)0x7FFF) +
- (getpid()%(unsigned)100);
- name_trn_id = (name_trn_id+1) % (unsigned)0x7FFF;
-
- nmb->header.name_trn_id = name_trn_id;
- nmb->header.opcode = opcode;
- nmb->header.response = False;
- nmb->header.nm_flags.bcast = bcast;
- nmb->header.nm_flags.recursion_available = CanRecurse;
- nmb->header.nm_flags.recursion_desired = recurse;
- nmb->header.nm_flags.trunc = False;
- nmb->header.nm_flags.authoritative = False;
- nmb->header.rcode = 0;
- nmb->header.qdcount = 1;
- nmb->header.ancount = 0;
- nmb->header.nscount = 0;
- nmb->header.arcount = (quest_type==NMB_REG || quest_type==NMB_REL) ? 1 : 0;
-
- make_nmb_name(&nmb->question.question_name,name,name_type,scope);
-
- nmb->question.question_type = quest_type;
- nmb->question.question_class = 0x1;
-
- if (quest_type == NMB_REG || quest_type == NMB_REL)
+ for (d = subnetlist; d; d = d->next)
+ {
+ struct response_record *n, *nextn;
+
+ for (n = d->responselist; n; n = nextn)
{
- nmb->additional = &additional_rec;
- bzero((char *)nmb->additional,sizeof(*nmb->additional));
-
- nmb->additional->rr_name = nmb->question.question_name;
- nmb->additional->rr_type = nmb->question.question_type;
- nmb->additional->rr_class = nmb->question.question_class;
-
- nmb->additional->ttl = quest_type == NMB_REG ? lp_max_ttl() : 0;
- nmb->additional->rdlength = 6;
- nmb->additional->rdata[0] = nb_flags;
- putip(&nmb->additional->rdata[2],(char *)iface_ip(to_ip));
+ nextn = n->next;
+
+ if (n->repeat_time <= time(NULL))
+ {
+ if (n->repeat_count > 0)
+ {
+ /* resend the entry */
+ initiate_netbios_packet(&n->response_id, n->fd, n->quest_type,
+ n->name.name, n->name.name_type,
+ n->nb_flags, n->bcast, n->recurse, n->send_ip);
+
+ n->repeat_time += n->repeat_interval; /* XXXX ms needed */
+ n->repeat_count--;
+
+ }
+ else
+ {
+ DEBUG(4,("timeout response %d for %s %s\n",
+ n->response_id, namestr(&n->name),
+ inet_ntoa(n->send_ip)));
+
+ dead_netbios_entry (d,n); /* process the non-response */
+ remove_response_record(d,n); /* remove the non-response */
+
+ continue;
+ }
+ }
}
-
- p.ip = to_ip;
- p.port = NMB_PORT;
- p.fd = fd;
- p.timestamp = time(NULL);
- p.packet_type = NMB_PACKET;
-
- if (!send_packet(&p))
- return(0);
-
- return(name_trn_id);
+ }
}
@@ -241,10 +221,18 @@
name server instead, if it exists. if wins is false, and there has been no
WINS server specified, the packet will NOT be sent.
****************************************************************************/
-void queue_netbios_pkt_wins(int fd,int quest_type,enum cmd_type cmd,
- char *name,int name_type,int nb_flags,
- BOOL bcast,BOOL recurse,struct in_addr to_ip)
-{
+struct response_record *queue_netbios_pkt_wins(struct subnet_record *d,
+ int fd,int quest_type,enum state_type state,
+ char *name,int name_type,int nb_flags, time_t ttl,
+ BOOL bcast,BOOL recurse,
+ struct in_addr send_ip, struct in_addr reply_to_ip)
+{
+ /* XXXX note: please see rfc1001.txt section 10 for details on this
+ function: it is currently inappropriate to use this - it will do
+ for now - once there is a clarification of B, M and P nodes and
+ which one samba is supposed to be
+ */
+
if ((!lp_wins_support()) && (*lp_wins_server()))
{
/* samba is not a WINS server, and we are using a WINS server */
@@ -254,7 +242,7 @@
if (!zero_ip(wins_ip))
{
bcast = False;
- to_ip = wins_ip;
+ send_ip = wins_ip;
}
else
{
@@ -264,38 +252,11 @@
}
}
- if (zero_ip(to_ip)) return;
-
- queue_netbios_packet(fd, quest_type, cmd,
- name, name_type, nb_flags,
- bcast, recurse, to_ip);
-}
-
-/****************************************************************************
- create a name query response record
- **************************************************************************/
-static struct name_response_record *
-make_name_query_record(enum cmd_type cmd,int id,int fd,char *name,int type,
- BOOL bcast,BOOL recurse,struct in_addr ip)
-{
- struct name_response_record *n;
-
- if (!name || !name[0]) return NULL;
-
- if (!(n = (struct name_response_record *)malloc(sizeof(*n))))
- return(NULL);
-
- n->response_id = id;
- n->cmd_type = cmd;
- n->fd = fd;
- make_nmb_name(&n->name, name, type, scope);
- n->bcast = bcast;
- n->recurse = recurse;
- n->to_ip = ip;
- n->start_time = time(NULL);
- n->num_msgs = 0;
+ if (zero_ip(send_ip)) return NULL;
- return n;
+ return queue_netbios_packet(d,fd, quest_type, state,
+ name, name_type, nb_flags, ttl,
+ bcast, recurse, send_ip, reply_to_ip);
}
@@ -305,310 +266,33 @@
master browsers (WORKGROUP(1d or 1b) or __MSBROWSE__(1)) to get
complete lists across a wide area network
****************************************************************************/
-void queue_netbios_packet(int fd,int quest_type,enum cmd_type cmd,char *name,
- int name_type,int nb_flags,BOOL bcast,BOOL recurse,
- struct in_addr to_ip)
-{
- uint16 id = initiate_netbios_packet(fd, quest_type, name, name_type,
- nb_flags, bcast, recurse, to_ip);
- struct name_response_record *n;
-
- if (id == 0) return;
-
- if ((n =
- make_name_query_record(cmd,id,fd,name,name_type,bcast,recurse,to_ip)))
- {
- add_response_record(n);
- }
-}
-
-
-/****************************************************************************
- find a response in the name query response list
- **************************************************************************/
-struct name_response_record *find_name_query(uint16 id)
-{
- struct name_response_record *n;
-
- for (n = nameresponselist; n; n = n->next)
- {
- if (n->response_id == id) {
- return n;
- }
- }
-
- return NULL;
-}
-
-
-/*******************************************************************
- the global packet linked-list. incoming entries are added to the
- end of this list. it is supposed to remain fairly short so we
- won't bother with an end pointer.
- ******************************************************************/
-static struct packet_struct *packet_queue = NULL;
-
-/*******************************************************************
- queue a packet into the packet queue
- ******************************************************************/
-void queue_packet(struct packet_struct *packet)
-{
- struct packet_struct *p;
-
- if (!packet_queue) {
- packet->prev = NULL;
- packet->next = NULL;
- packet_queue = packet;
- return;
+struct response_record *queue_netbios_packet(struct subnet_record *d,
+ int fd,int quest_type,enum state_type state,char *name,
+ int name_type,int nb_flags, time_t ttl,
+ BOOL bcast,BOOL recurse,
+ struct in_addr send_ip, struct in_addr reply_to_ip)
+{
+ struct in_addr wins_ip = ipgrp;
+ struct response_record *n;
+ uint16 id = 0xffff;
+
+ /* ha ha. no. do NOT broadcast to 255.255.255.255: it's a pseudo address */
+ if (ip_equal(wins_ip, send_ip)) return NULL;
+
+ initiate_netbios_packet(&id, fd, quest_type, name, name_type,
+ nb_flags, bcast, recurse, send_ip);
+
+ if (id == 0xffff) {
+ DEBUG(4,("did not initiate netbios packet: %s\n", inet_ntoa(send_ip)));
+ return NULL;
}
- /* find the bottom */
- for (p=packet_queue;p->next;p=p->next) ;
-
- p->next = packet;
- packet->next = NULL;
- packet->prev = p;
-}
-
-/*******************************************************************
- run elements off the packet queue till its empty
- ******************************************************************/
-void run_packet_queue()
-{
- struct packet_struct *p;
-
- while ((p=packet_queue))
+ if ((n = make_response_queue_record(state,id,fd,
+ quest_type,name,name_type,nb_flags,ttl,
+ bcast,recurse,send_ip,reply_to_ip)))
{
- switch (p->packet_type)
- {
- case NMB_PACKET:
- process_nmb(p);
- break;
-
- case DGRAM_PACKET:
- process_dgram(p);
- break;
- }
-
- packet_queue = packet_queue->next;
- if (packet_queue) packet_queue->prev = NULL;
- free_packet(p);
+ add_response_record(d,n);
+ return n;
}
+ return NULL;
}
-
-/****************************************************************************
- listens for NMB or DGRAM packets, and queues them
- ***************************************************************************/
-void listen_for_packets(BOOL run_election)
-{
- fd_set fds;
- int selrtn;
- struct timeval timeout;
-
- FD_ZERO(&fds);
- FD_SET(ClientNMB,&fds);
- FD_SET(ClientDGRAM,&fds);
-
- /* during elections we need to send election packets at one
- second intervals */
-
- timeout.tv_sec = run_election ? 1 : NMBD_SELECT_LOOP;
- timeout.tv_usec = 0;
-
- selrtn = sys_select(&fds,&timeout);
-
- if (FD_ISSET(ClientNMB,&fds))
- {
- struct packet_struct *packet = read_packet(ClientNMB, NMB_PACKET);
- if (packet) {
-#if 1
- if (ismyip(packet->ip) &&
- (packet->port == NMB_PORT || packet->port == DGRAM_PORT)) {
- DEBUG(5,("discarding own packet from %s:%d\n",
- inet_ntoa(packet->ip),packet->port));
- free_packet(packet);
- } else
-#endif
- {
- queue_packet(packet);
- }
- }
- }
-
- if (FD_ISSET(ClientDGRAM,&fds))
- {
- struct packet_struct *packet = read_packet(ClientDGRAM, DGRAM_PACKET);
- if (packet) {
-#if 1
- if (ismyip(packet->ip) &&
- (packet->port == NMB_PORT || packet->port == DGRAM_PORT)) {
- DEBUG(5,("discarding own packet from %s:%d\n",
- inet_ntoa(packet->ip),packet->port));
- free_packet(packet);
- } else
-#endif
- {
- queue_packet(packet);
- }
- }
- }
-}
-
-
-
-/****************************************************************************
-interpret a node status response. this is pretty hacked: we need two bits of
-info. a) the name of the workgroup b) the name of the server. it will also
-add all the names it finds into the namelist.
-****************************************************************************/
-BOOL interpret_node_status(char *p, struct nmb_name *name,int t,
- char *serv_name, struct in_addr ip)
-{
- int level = t==0x20 ? 4 : 0;
- int numnames = CVAL(p,0);
- BOOL found = False;
-
- DEBUG(level,("received %d names\n",numnames));
-
- p += 1;
-
- if (serv_name) *serv_name = 0;
-
- while (numnames--)
- {
- char qname[17];
- int type;
- fstring flags;
- int nb_flags;
-
- BOOL group = False;
- BOOL add = False;
-
- *flags = 0;
-
- StrnCpy(qname,p,15);
- type = CVAL(p,15);
- nb_flags = p[16];
- trim_string(qname,NULL," ");
-
- p += 18;
-
- if (NAME_GROUP (nb_flags)) { strcat(flags,"<GROUP> "); group=True;}
- if (NAME_BFLAG (nb_flags)) { strcat(flags,"B "); }
- if (NAME_PFLAG (nb_flags)) { strcat(flags,"P "); }
- if (NAME_MFLAG (nb_flags)) { strcat(flags,"M "); }
- if (NAME__FLAG (nb_flags)) { strcat(flags,"_ "); }
- if (NAME_DEREG (nb_flags)) { strcat(flags,"<DEREGISTERING> "); }
- if (NAME_CONFLICT (nb_flags)) { strcat(flags,"<CONFLICT> "); add=True;}
- if (NAME_ACTIVE (nb_flags)) { strcat(flags,"<ACTIVE> "); add=True; }
- if (NAME_PERMANENT(nb_flags)) { strcat(flags,"<PERMANENT> "); add=True;}
-
- /* might as well update our namelist while we're at it */
- if (add)
- {
- struct in_addr nameip;
- enum name_source src;
-
- if (ismyip(ip)) {
- nameip = ipzero;
- src = SELF;
- } else {
- nameip = ip;
- src = STATUS_QUERY;
- }
- add_netbios_entry(qname,type,nb_flags,2*60*60,src,nameip,True);
- }
-
- /* we want the server name */
- if (serv_name && !*serv_name && !group && t == 0)
- {
- StrnCpy(serv_name,qname,15);
- serv_name[15] = 0;
- }
-
- /* looking for a name and type? */
- if (name && !found && (t == type))
- {
- /* take a guess at some of the name types we're going to ask for.
- evaluate whether they are group names or no... */
- if (((t == 0x1b || t == 0x1d ) && !group) ||
- ((t == 0x20 || t == 0x1c || t == 0x1e) && group))
- {
- found = True;
- make_nmb_name(name,qname,type,scope);
- }
- }
-
- DEBUG(level,("\t%s(0x%x)\t%s\n",qname,type,flags));
- }
- DEBUG(level,("num_good_sends=%d num_good_receives=%d\n",
- IVAL(p,20),IVAL(p,24)));
- return found;
-}
-
-
-/****************************************************************************
- construct and send a netbios DGRAM
-
- Note that this currently sends all answers to port 138. thats the
- wrong things to do! I should send to the requestors port. XXX
- **************************************************************************/
-BOOL send_mailslot_reply(char *mailslot,int fd,char *buf,int len,char *srcname,
- char *dstname,int src_type,int dest_type,
- struct in_addr dest_ip,struct in_addr src_ip)
-{
- struct packet_struct p;
- struct dgram_packet *dgram = &p.packet.dgram;
- char *ptr,*p2;
- char tmp[4];
-
- bzero((char *)&p,sizeof(p));
-
- dgram->header.msg_type = 0x11; /* DIRECT GROUP DATAGRAM */
- dgram->header.flags.node_type = M_NODE;
- dgram->header.flags.first = True;
- dgram->header.flags.more = False;
- dgram->header.dgm_id = name_trn_id++;
- dgram->header.source_ip = src_ip;
- dgram->header.source_port = DGRAM_PORT;
- dgram->header.dgm_length = 0; /* let build_dgram() handle this */
- dgram->header.packet_offset = 0;
-
- make_nmb_name(&dgram->source_name,srcname,src_type,scope);
- make_nmb_name(&dgram->dest_name,dstname,dest_type,scope);
-
- ptr = &dgram->data[0];
-
- /* now setup the smb part */
- ptr -= 4; /* XXX ugliness because of handling of tcp SMB length */
- memcpy(tmp,ptr,4);
- set_message(ptr,17,17 + len,True);
- memcpy(ptr,tmp,4);
-
- CVAL(ptr,smb_com) = SMBtrans;
- SSVAL(ptr,smb_vwv1,len);
- SSVAL(ptr,smb_vwv11,len);
- SSVAL(ptr,smb_vwv12,70 + strlen(mailslot));
- SSVAL(ptr,smb_vwv13,3);
- SSVAL(ptr,smb_vwv14,1);
- SSVAL(ptr,smb_vwv15,1);
- SSVAL(ptr,smb_vwv16,2);
- p2 = smb_buf(ptr);
- strcpy(p2,mailslot);
- p2 = skip_string(p2,1);
-
- memcpy(p2,buf,len);
- p2 += len;
-
- dgram->datasize = PTR_DIFF(p2,ptr+4); /* +4 for tcp length */
-
- p.ip = dest_ip;
- p.port = DGRAM_PORT;
- p.fd = ClientDGRAM;
- p.timestamp = time(NULL);
- p.packet_type = DGRAM_PACKET;
-
- return(send_packet(&p));
-}
-
-
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/nameresp.doc samba-1.9.16alpha11/source/nameresp.doc
--- samba-1.9.16alpha10/source/nameresp.doc Thu Jan 1 10:00:00 1970
+++ samba-1.9.16alpha11/source/nameresp.doc Thu Jul 18 20:53:15 1996
@@ -0,0 +1,151 @@
+the netbios expected response code is a key part of samba's NetBIOS
+handling capabilities. it allows samba to carry on dealing with
+other things while expecting a response from one or more hosts.
+
+this allows samba to simultaneously deal with registering its names
+with another WINS server, register its names on its local subnets,
+query any hosts that have registered with samba in its capacity as
+a WINS server, and at a later date it will be also be able handle
+END-NODE CHALLENGES (see rfc1001.txt 15.2.2.2 and 15.2.2.3 - secured
+NBNS functionality).
+
+all at once!
+
+when a netbios packet is sent out by samba and it expects a response,
+a record of all the relevant information is kept (most importantly,
+the unique transaction id associated which will come back to us in
+a response packet is recorded, and also recorded is the reason that
+the original packet was sent out by samba in the first place!).
+
+if a response is received, then the unique transaction identifier
+returned in the response packet is searched for in the expected
+response records. the record indicates why the initial request was
+made (and therefore the type of response can be verified) and
+appropriate action can be taken.
+
+when no responses, after a number of retries, are not received, then
+samba may take appropriate action. this is a crucial part of samba's
+operation: for a key number of NetBIOS operations, no response is an
+implicit positive response.
+
+module nameresp deals with the initial transmission, re-transmission
+and time-out of netbios response records.
+
+module namedbresp deals with the maintenance of the list of expected
+responses - creation, finding and removal.
+
+
+/*************************************************************************
+ queue_netbios_packet()
+ *************************************************************************/
+
+this function is responsible for sending out a netbios packet, and then
+making a record of the information that was sent out. a response will
+be expected later (or not, as the case may be).
+
+if a response is received, response_netbios_packet() will deal with it.
+otherwise, it will be dealt with in expire_netbios_response_entries().
+
+
+/*************************************************************************
+ queue_netbios_pkt_wins()
+ *************************************************************************/
+
+this function is a wrapper around queue_netbios_packet(). there is
+some confusion about B, M and P nodes (see rfc1001.txt section 10) -
+confusion introduced by luke :-) - which needs sorting out.
+
+for example, rfc1001.txt 15.2.3 - an M node must attempt to register a
+name first as a B node, then attempt to register as an M node. negative
+responses on either of these attempts is a failure to register the
+name.
+
+this is NOT the case with a P node.
+
+
+/*************************************************************************
+ expire_netbios_response_entries()
+ *************************************************************************/
+
+this function is responsible for dealing with queued response records
+that have not received a response packet matching their unique
+transaction id.
+
+if the retry count for any record is non-zero, and its time-out period
+has expired, the retry count is reduced, the time-out period is stepped
+forward and the packet is re-transmitted (from the information stored
+in the queued response record) with the same unique transaction id of
+the initial attempt at soliciting a response.
+
+if the retry count is zero, then the packet is assumed to have expired.
+dead_netbios_entry() is called to deal with the possibility of an error
+or a problem (or in certain instances, no answer is an implicit
+positive response!).
+
+the expected response record is then deleted, and the number of expected
+responses reduced. when this count gets to zero, listen_for_packets()
+will no longer time-out for 1 second on account of expecting response
+packets.
+
+
+/*************************************************************************
+ dead_netbios_entry()
+ *************************************************************************/
+
+this function is responsible for dealing with the case when a NetBIOS
+response to a packet sent out by samba was not received. for certain
+transactions, this may be normal. for others, under certain conditions
+it may constitute either an error or a problem with or failure of one
+or more hosts.
+
+- NAME_QUERY_CONFIRM
+
+when a samba 'state' of type NAME_QUERY_CONFIRM is sent, a response
+may or may not be forthcoming. if no response is received to a unique
+name, then the record is removed from samba's WINS database. non-unique
+names are simply expected to die off on a time-to-live basis (see
+rfc1001.txt 15.1.3.4)
+
+query_refresh_names() issues this samba 'state'
+response_name_query_sync() deals with responses to NAME_QUERY_CONFIRM.
+
+- NAME_QUERY_MST_CHK
+
+when a samba 'state' of type NAME_QUERY_MST_CHK is sent, and a response
+is not received, this implies that a master browser will have failed.
+remedial action may need to be taken, for example if samba is a member
+of that workgroup and it is also a potential master browser it could
+force an election.
+
+check_master_browser() issues this samba 'state'.
+response_process() does nothing if a response is received. this is normal.
+
+- NAME_RELEASE
+
+when a samba 'state' of type NAME_RELEASE is sent, and a response is
+not received, it is assumed to be acceptable to release the name. if the
+original response was sent to another WINS server, then that WINS server
+may be inaccessible or may have failed. if so, then at a later date
+samba should take this into account (see rfc1001.txt 10.3).
+
+remove_name_entry() issues this samba 'state'
+response_name_rel() deals with responses to NAME_RELEASE.
+
+- NAME_REGISTER
+
+when a samba 'state' of type NAME_REGISTER is sent, and a response is
+not received, if the registration was done by broadcast, it is assumed
+that there are no objections to the registration of this name, and samba
+adds the name to the appropriate subnet record name database. if the
+registration was point-to-point (i.e with another WINS server) then that
+WINS server may be inaccessible or may have failed. if so, then at a later
+date samba should take this into account (see rfc1001.txt 10.3).
+
+add_my_name_entry() issues this samba 'state'
+response_name_reg() deals with responses to NAME_REGISTER.
+
+no action is taken for any other kinds of samba 'states' if a response
+is not received. this is not to say that action may not be appropriate,
+just that it's not been looked at yet :-)
+
+
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/nameserv.c samba-1.9.16alpha11/source/nameserv.c
--- samba-1.9.16alpha10/source/nameserv.c Mon Jun 10 15:18:56 1996
+++ samba-1.9.16alpha11/source/nameserv.c Thu Jul 18 20:53:15 1996
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
NBT netbios routines and daemon - version 2
- Copyright (C) Andrew Tridgell 1994-1995
+ Copyright (C) Andrew Tridgell 1994-1996
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,225 +18,151 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ Module name: nameserv.c
+
Revision History:
14 jan 96: lkcl@pires.co.uk
added multiple workgroup domain master support
+ 04 jul 96: lkcl@pires.co.uk
+ module nameserv contains name server management functions
*/
#include "includes.h"
extern int ClientNMB;
-extern int ClientDGRAM;
extern int DEBUGLEVEL;
extern pstring scope;
-extern BOOL CanRecurse;
extern pstring myname;
+extern pstring ServerComment;
extern struct in_addr ipzero;
extern struct in_addr ipgrp;
-/* netbios names database */
-struct name_record *namelist;
-
-#define GET_TTL(ttl) ((ttl)?MIN(ttl,lp_max_ttl()):lp_max_ttl())
+extern struct subnet_record *subnetlist;
/****************************************************************************
- true if two netbios names are equal
-****************************************************************************/
-static BOOL name_equal(struct nmb_name *n1,struct nmb_name *n2)
-{
- if (n1->name_type != n2->name_type) return(False);
-
- return(strequal(n1->name,n2->name) && strequal(n1->scope,n2->scope));
-}
-
-/****************************************************************************
- add a netbios name into the namelist
- **************************************************************************/
-static void add_name(struct name_record *n)
-{
- struct name_record *n2;
-
- if (!namelist)
- {
- namelist = n;
- n->prev = NULL;
- n->next = NULL;
- return;
- }
+ remove an entry from the name list
- for (n2 = namelist; n2->next; n2 = n2->next) ;
+ note: the name will _always_ be removed: it's just a matter of when.
+ XXXX at present, the name is removed _even_ if a WINS server says keep it.
- n2->next = n;
- n->next = NULL;
- n->prev = n2;
-}
-
-/****************************************************************************
- remove a name from the namelist. The pointer must be an element just
- retrieved
- **************************************************************************/
-void remove_name(struct name_record *n)
+ ****************************************************************************/
+void remove_name_entry(struct subnet_record *d, char *name,int type)
{
- struct name_record *nlist = namelist;
+ /* XXXX BUG: if samba is offering WINS support, it should still broadcast
+ a de-registration packet to the local subnet before removing the
+ name from its local-subnet name database. */
- while (nlist && nlist != n) nlist = nlist->next;
+ struct name_record n;
+ struct name_record *n2=NULL;
+
+ make_nmb_name(&n.name,name,type,scope);
- if (nlist)
+ if ((n2 = find_name_search(&d, &n.name, FIND_SELF, ipzero)))
{
- if (nlist->next) nlist->next->prev = nlist->prev;
- if (nlist->prev) nlist->prev->next = nlist->next;
- free(nlist);
- }
-}
+ /* check name isn't already being de-registered */
+ if (NAME_DEREG(n2->nb_flags))
+ return;
+ /* mark the name as in the process of deletion. */
+ n2->nb_flags &= NB_DEREG;
+ }
-/****************************************************************************
- find a name in the domain database namelist
- search can be:
- FIND_SELF - look for names the samba server has added for itself
- FIND_GLOBAL - the name can be anyone. first look on the client's
- subnet, then the server's subnet, then all subnets.
- **************************************************************************/
-static struct name_record *find_name_search(struct nmb_name *name,
- enum name_search search,
- struct in_addr ip)
-{
- struct name_record *ret;
-
- for (ret = namelist; ret; ret = ret->next)
+ if (ip_equal(d->bcast_ip, ipgrp))
+ {
+ if (lp_wins_support())
{
- if (!name_equal(&ret->name,name)) continue;
-
- if (search == FIND_SELF && ret->source != SELF) continue;
-
- return ret;
+ /* we are a WINS server. */
+ /* XXXX assume that if we are a WINS server that we are therefore
+ not pointing to another WINS server as well. this may later NOT
+ actually be true
+ */
+ remove_netbios_name(d,name,type,SELF,ipzero);
+ }
+ else
+ {
+ /* not a WINS server: cannot just remove our own names: we have to
+ release them on the network first. ask permission from the WINS
+ server, or if no reply is received, then we can remove the name */
+
+ queue_netbios_pkt_wins(d,ClientNMB,NMB_REL,NAME_RELEASE,
+ name, type, 0, 0,
+ False, True, ipzero, ipzero);
}
-
- return NULL;
+ }
+ else
+ {
+ /* local interface: cannot just remove our own names: we have to
+ release them on the network first. once no reply is received,
+ then we can remove the name. */
+
+ queue_netbios_packet(d,ClientNMB,NMB_REL,NAME_RELEASE,
+ name, type, 0, 0,
+ True, True, d->bcast_ip, d->bcast_ip);
+ }
}
/****************************************************************************
- dump a copy of the name table
- **************************************************************************/
-void dump_names(void)
-{
- struct name_record *n;
- time_t t = time(NULL);
-
- DEBUG(3,("Dump of local name table:\n"));
+ add an entry to the name list
- for (n = namelist; n; n = n->next)
- {
- DEBUG(3,("%s %s TTL=%d NBFLAGS=%2x\n",
- namestr(&n->name),
- inet_ntoa(n->ip),
- n->death_time?n->death_time-t:0,
- n->nb_flags));
- }
-}
-
+ big note: our name will _always_ be added (if there are no objections).
+ it's just a matter of when this will be done (e.g after a time-out).
-/****************************************************************************
- remove an entry from the name list
****************************************************************************/
-void remove_netbios_name(char *name,int type, enum name_source source,
- struct in_addr ip)
+void add_my_name_entry(struct subnet_record *d,char *name,int type,int nb_flags)
{
- struct nmb_name nn;
- struct name_record *n;
-
- make_nmb_name(&nn, name, type, scope);
- n = find_name_search(&nn, FIND_GLOBAL, ip);
-
- if (n && n->source == source) remove_name(n);
-}
+ BOOL re_reg = False;
+ struct nmb_name n;
+ if (!d) return;
-/****************************************************************************
- add an entry to the name list
- ****************************************************************************/
-struct name_record *add_netbios_entry(char *name, int type, int nb_flags,
- int ttl,
- enum name_source source,
- struct in_addr ip,
- BOOL new_only)
-{
- struct name_record *n;
- struct name_record *n2=NULL;
-
- n = (struct name_record *)malloc(sizeof(*n));
- if (!n) return(NULL);
+ /* not that it particularly matters, but if the SELF name already exists,
+ it must be re-registered, rather than just registered */
- bzero((char *)n,sizeof(*n));
+ make_nmb_name(&n, name, type, scope);
+ if (find_name(d->namelist, &n, SELF))
+ re_reg = True;
- make_nmb_name(&n->name,name,type,scope);
+ /* XXXX BUG: if samba is offering WINS support, it should still add the
+ name entry to a local-subnet name database. see rfc1001.txt 15.1.1 p28
+ regarding the point about M-nodes. */
- if ((n2 = find_name_search(&n->name, FIND_GLOBAL, new_only?ipzero:ip)))
+ if (ip_equal(d->bcast_ip, ipgrp))
{
- free(n);
- if (new_only || (n2->source==SELF && source!=SELF)) return n2;
- n = n2;
- }
-
- if (ttl) n->death_time = time(NULL)+ttl*3;
- n->ip = ip;
- n->nb_flags = nb_flags;
- n->source = source;
-
- if (!n2) add_name(n);
-
- DEBUG(3,("Added netbios name %s at %s ttl=%d nb_flags=%2x\n",
- namestr(&n->name),inet_ntoa(ip),ttl,nb_flags));
-
- return(n);
-}
-
-
-/****************************************************************************
- remove an entry from the name list
- ****************************************************************************/
-void remove_name_entry(char *name,int type)
-{
- if (lp_wins_support())
+ if (lp_wins_support())
{
/* we are a WINS server. */
- remove_netbios_name(name,type,SELF,ipzero);
+ /* XXXX assume that if we are a WINS server that we are therefore
+ not pointing to another WINS server as well. this may later NOT
+ actually be true
+ */
+
+ DEBUG(4,("samba as WINS server adding: "));
+ /* this will call add_netbios_entry() */
+ name_register_work(d, name, type, nb_flags,0, ipzero, False);
+ }
+ else
+ {
+ /* a time-to-live allows us to refresh this name with the WINS server. */
+ queue_netbios_pkt_wins(d,ClientNMB,
+ re_reg ? NMB_REG_REFRESH : NMB_REG, NAME_REGISTER,
+ name, type, nb_flags, GET_TTL(0),
+ False, True, ipzero, ipzero);
}
+ }
else
- {
- struct in_addr ip;
- ip = ipzero;
-
- queue_netbios_pkt_wins(ClientNMB,NMB_REL,NAME_RELEASE,
- name, type, 0,
- False, True, ip);
- }
-}
-
-
-/****************************************************************************
- add an entry to the name list
- ****************************************************************************/
-void add_name_entry(char *name,int type,int nb_flags)
-{
- /* always add our own entries */
- add_netbios_entry(name,type,nb_flags,0,SELF,ipzero,False);
-
- if (!lp_wins_support())
- {
- struct in_addr ip;
- ip = ipzero;
-
- queue_netbios_pkt_wins(ClientNMB,NMB_REG,NAME_REGISTER,
- name, type, nb_flags,
- False, True, ip);
- }
+ {
+ /* broadcast the packet, but it comes from ipzero */
+ queue_netbios_packet(d,ClientNMB,
+ re_reg ? NMB_REG_REFRESH : NMB_REG, NAME_REGISTER,
+ name, type, nb_flags, GET_TTL(0),
+ True, True, d->bcast_ip, ipzero);
+ }
}
@@ -245,815 +171,161 @@
**************************************************************************/
void add_my_names(void)
{
- struct in_addr ip;
+ BOOL wins = lp_wins_support();
+ struct subnet_record *d;
- ip = ipzero;
-
- add_name_entry(myname,0x20,NB_ACTIVE);
- add_name_entry(myname,0x03,NB_ACTIVE);
- add_name_entry(myname,0x00,NB_ACTIVE);
- add_name_entry(myname,0x1f,NB_ACTIVE);
-
- add_netbios_entry("*",0x0,NB_ACTIVE,0,SELF,ip,False);
- add_netbios_entry("__SAMBA__",0x20,NB_ACTIVE,0,SELF,ip,False);
- add_netbios_entry("__SAMBA__",0x00,NB_ACTIVE,0,SELF,ip,False);
-
- if (lp_wins_support()) {
- /* the 0x1c name gets added by any WINS server it seems */
- add_name_entry(my_workgroup(),0x1c,NB_ACTIVE|NB_GROUP);
- }
-}
-
-/****************************************************************************
- remove all the samba names... from a WINS server if necessary.
- **************************************************************************/
-void remove_my_names()
-{
- struct name_record *n;
-
- for (n = namelist; n; n = n->next)
- {
- if (n->source == SELF)
- {
- /* get all SELF names removed from the WINS server's database */
- remove_name_entry(n->name.name, n->name.name_type);
- }
- }
-}
-
-
-/*******************************************************************
- refresh my own names
- ******************************************************************/
-void refresh_my_names(time_t t)
-{
- static time_t lasttime = 0;
+ struct in_addr ip = ipzero;
- if (t - lasttime < REFRESH_TIME)
- return;
- lasttime = t;
+ /* each subnet entry, including WINS pseudo-subnet, has SELF names */
- add_my_names();
-}
+ /* XXXX if there was a transport layer added to samba (ipx/spx etc) then
+ there would be yet _another_ for-loop, this time on the transport type
+ */
-/*******************************************************************
- expires old names in the namelist
- ******************************************************************/
-void expire_names(time_t t)
-{
- struct name_record *n;
- struct name_record *next;
-
- /* expire old names */
- for (n = namelist; n; n = next)
- {
- if (n->death_time && n->death_time < t)
- {
- DEBUG(3,("Removing dead name %s\n", namestr(&n->name)));
-
- next = n->next;
-
- if (n->prev) n->prev->next = n->next;
- if (n->next) n->next->prev = n->prev;
-
- if (namelist == n) namelist = n->next;
-
- free(n);
- }
- else
- {
- next = n->next;
- }
- }
-}
-
-
-/****************************************************************************
- response for a reg release received
- **************************************************************************/
-void response_name_release(struct packet_struct *p)
-{
- struct nmb_packet *nmb = &p->packet.nmb;
- char *name = nmb->question.question_name.name;
- int type = nmb->question.question_name.name_type;
-
- DEBUG(4,("response name release received\n"));
-
- if (nmb->header.rcode == 0 && nmb->answers->rdata)
- {
- struct in_addr found_ip;
- putip((char*)&found_ip,&nmb->answers->rdata[2]);
-
- if (ismyip(found_ip))
- {
- remove_netbios_name(name,type,SELF,found_ip);
- }
- }
- else
- {
- DEBUG(1,("name registration for %s rejected!\n",
- namestr(&nmb->question.question_name)));
- }
-}
-
-
-/****************************************************************************
- reply to a name release
- ****************************************************************************/
-void reply_name_release(struct packet_struct *p)
-{
- struct nmb_packet *nmb = &p->packet.nmb;
- struct in_addr ip;
- int rcode=0;
- int opcode = nmb->header.opcode;
- int nb_flags = nmb->additional->rdata[0];
- BOOL bcast = nmb->header.nm_flags.bcast;
- struct name_record *n;
- char rdata[6];
-
- putip((char *)&ip,&nmb->additional->rdata[2]);
-
- DEBUG(3,("Name release on name %s rcode=%d\n",
- namestr(&nmb->question.question_name),rcode));
-
- n = find_name_search(&nmb->question.question_name, FIND_GLOBAL, ip);
-
- /* XXXX under what conditions should we reject the removal?? */
- if (n && n->nb_flags == nb_flags)
- {
- /* success = True;
- rcode = 6; */
-
- remove_name(n);
- n = NULL;
- }
-
- if (bcast) return;
-
- rdata[0] = nb_flags;
- rdata[1] = 0;
- putip(&rdata[2],(char *)&ip);
-
- /* Send a NAME RELEASE RESPONSE */
- reply_netbios_packet(p,nmb->header.name_trn_id,
- rcode,opcode,True,
- &nmb->question.question_name,
- nmb->question.question_type,
- nmb->question.question_class,
- 0,
- rdata, 6);
-}
+ for (d = subnetlist; d; d = d->next)
+ {
+ BOOL wins_iface = ip_equal(d->bcast_ip, ipgrp);
+ if (!d->my_interface && !wins_iface) continue;
-/****************************************************************************
- response for a reg request received
- **************************************************************************/
-void response_name_reg(struct packet_struct *p)
-{
- struct nmb_packet *nmb = &p->packet.nmb;
- char *name = nmb->question.question_name.name;
- int type = nmb->question.question_name.name_type;
-
- DEBUG(4,("response name registration received!\n"));
-
- if (nmb->header.rcode == 0 && nmb->answers->rdata)
- {
- int nb_flags = nmb->answers->rdata[0];
- struct in_addr found_ip;
- int ttl = nmb->answers->ttl;
- enum name_source source = REGISTER;
-
- putip((char*)&found_ip,&nmb->answers->rdata[2]);
-
- if (ismyip(found_ip)) source = SELF;
-
- add_netbios_entry(name,type,nb_flags,ttl,source,found_ip,True);
+ add_my_name_entry(d, myname,0x20,NB_ACTIVE);
+ add_my_name_entry(d, myname,0x03,NB_ACTIVE);
+ add_my_name_entry(d, myname,0x00,NB_ACTIVE);
+ add_my_name_entry(d, myname,0x1f,NB_ACTIVE);
+
+ /* these names are added permanently (ttl of zero) and will NOT be
+ refreshed with the WINS server */
+ add_netbios_entry(d,"*",0x0,NB_ACTIVE,0,SELF,ip,False,wins);
+ add_netbios_entry(d,"__SAMBA__",0x20,NB_ACTIVE,0,SELF,ip,False,wins);
+ add_netbios_entry(d,"__SAMBA__",0x00,NB_ACTIVE,0,SELF,ip,False,wins);
+
+ if (!wins_iface && lp_domain_logons() && lp_domain_master()) {
+ /* XXXX the 0x1c is apparently something to do with domain logons */
+ add_my_name_entry(d, my_workgroup(),0x1c,NB_ACTIVE|NB_GROUP);
}
- else
+ }
+ if (lp_domain_master() && (d = find_subnet(ipgrp)))
+ {
+ struct work_record *work = find_workgroupstruct(d, lp_workgroup(), True);
+ if (work && work->state == MST_NONE)
{
- DEBUG(1,("name registration for %s rejected!\n",
- namestr(&nmb->question.question_name)));
+ work->state = MST_DOMAIN_NONE;
+ become_master(d, work);
}
+ }
}
/****************************************************************************
- reply to a reg request
+ remove all the samba names... from a WINS server if necessary.
**************************************************************************/
-void reply_name_reg(struct packet_struct *p)
+void remove_my_names()
{
- struct nmb_packet *nmb = &p->packet.nmb;
- struct nmb_name *question = &nmb->question.question_name;
-
- struct nmb_name *reply_name = question;
- char *qname = question->name;
- int name_type = question->name_type;
- int name_class = nmb->question.question_class;
-
- BOOL bcast = nmb->header.nm_flags.bcast;
-
- int ttl = GET_TTL(nmb->additional->ttl);
- int nb_flags = nmb->additional->rdata[0];
- BOOL group = NAME_GROUP(nb_flags);
- int rcode = 0;
- int opcode = nmb->header.opcode;
-
- struct name_record *n = NULL;
- BOOL success = True;
- BOOL recurse = True; /* true if samba replies yes/no: false if caller */
- /* must challenge the current owner */
- char rdata[6];
-
- struct in_addr ip, from_ip;
-
- DEBUG(3,("Name registration for name %s at %s rcode=%d\n",
- namestr(question),inet_ntoa(ip),rcode));
-
- putip((char *)&from_ip,&nmb->additional->rdata[2]);
- ip = from_ip;
-
- if (group)
- {
- /* apparently we should return 255.255.255.255 for group queries
- (email from MS) */
- ip = ipgrp;
- }
-
- /* see if the name already exists */
- n = find_name_search(question, FIND_GLOBAL, from_ip);
-
- if (n)
- {
- if (!group) /* unique names */
- {
- if (n->source == SELF || NAME_GROUP(n->nb_flags))
- {
- /* no-one can register one of samba's names, nor can they
- register a name that's a group name as a unique name */
-
- rcode = 6;
- success = False;
- }
- else if(!ip_equal(ip, n->ip))
- {
- /* hm. this unique name doesn't belong to them. */
-
- /* XXXX rfc1001.txt says:
- * if we are doing secured WINS, we must send a Wait-Acknowledge
- * packet (WACK) to the person who wants the name, then do a
- * name query on the person who currently owns the unique name.
- * if the current owner is alive, the person who wants the name
- * can't have it. if they are not alive, they can.
- *
- * if we are doing non-secure WINS (which is much simpler) then
- * we send a message to the person wanting the name saying 'he
- * owns this name: i don't want to hear from you ever again
- * until you've checked with him if you can have it!'. we then
- * abandon the registration. once the person wanting the name
- * has checked with the current owner, they will repeat the
- * registration packet if the current owner is dead or doesn't
- * want the name.
- */
-
- /* non-secured WINS implementation: caller is responsible
- for checking with current owner of name, then getting back
- to us... IF current owner no longer owns the unique name */
-
- rcode = 0;
- success = False;
- recurse = False;
-
- /* we inform on the current owner to the caller (which is
- why it's non-secure */
-
- reply_name = &n->name;
-
- /* name_type = ?;
- name_class = ?;
- XXXX sorry, guys: i really can't see what name_type
- and name_class should be set to according to rfc1001 */
- }
- else
- {
- /* XXXX removed code that checked with the owner of a name */
-
- n->ip = ip;
- n->death_time = ttl?p->timestamp+ttl*3:0;
- DEBUG(3,("%s owner: %s\n",namestr(&n->name),inet_ntoa(n->ip)));
- }
- }
- else
- {
- /* refresh the name */
- if (n->source != SELF)
- {
- n->death_time = ttl?p->timestamp + ttl*3:0;
- }
- }
- }
- else
- {
- /* add the name to our subnet/name database */
- n = add_netbios_entry(qname,name_type,nb_flags,ttl,REGISTER,ip,True);
- }
-
- if (bcast) return;
-
- if (success)
- {
- update_from_reg(nmb->question.question_name.name,
- nmb->question.question_name.name_type, from_ip);
- }
-
- rdata[0] = nb_flags;
- rdata[1] = 0;
- putip(&rdata[2],(char *)&ip);
-
- /* Send a NAME REGISTRATION RESPONSE (pos/neg)
- or and END-NODE CHALLENGE REGISTRATION RESPONSE */
- reply_netbios_packet(p,nmb->header.name_trn_id,
- rcode,opcode,recurse,
- reply_name, name_type, name_class,
- ttl,
- rdata, 6);
-}
+ struct subnet_record *d;
-
-/****************************************************************************
- reply to a name status query
- ****************************************************************************/
-void reply_name_status(struct packet_struct *p)
-{
- struct nmb_packet *nmb = &p->packet.nmb;
- char *qname = nmb->question.question_name.name;
- int ques_type = nmb->question.question_name.name_type;
- char rdata[MAX_DGRAM_SIZE];
- char *countptr, *buf, *bufend;
- int names_added;
- struct name_record *n;
-
- DEBUG(3,("Name status for name %s %s\n",
- namestr(&nmb->question.question_name), inet_ntoa(p->ip)));
-
- n = find_name_search(&nmb->question.question_name,FIND_GLOBAL, p->ip);
-
- if (!n) return;
-
- /* XXXX hack, we should calculate exactly how many will fit */
- bufend = &rdata[MAX_DGRAM_SIZE] - 18;
- countptr = buf = rdata;
- buf += 1;
-
- names_added = 0;
-
- for (n = namelist ; n && buf < bufend; n = n->next)
- {
- int name_type = n->name.name_type;
-
- if (n->source != SELF) continue;
-
- /* start with first bit of putting info in buffer: the name */
-
- bzero(buf,18);
- sprintf(buf,"%-15.15s",n->name.name);
- strupper(buf);
-
- /* now check if we want to exclude other workgroup names
- from the response. if we don't exclude them, windows clients
- get confused and will respond with an error for NET VIEW */
-
- if (name_type >= 0x1b && name_type <= 0x20 &&
- ques_type >= 0x1b && ques_type <= 0x20)
+ for (d = subnetlist; d; d = d->next)
{
- if (!strequal(qname, n->name.name)) continue;
- }
-
- /* carry on putting name info in buffer */
-
- buf[15] = name_type;
- buf[16] = n->nb_flags;
-
- buf += 18;
-
- names_added++;
- }
-
- SCVAL(countptr,0,names_added);
-
- /* XXXXXXX we should fill in more fields of the statistics structure */
- bzero(buf,64);
- {
- extern int num_good_sends,num_good_receives;
- SIVAL(buf,20,num_good_sends);
- SIVAL(buf,24,num_good_receives);
- }
-
- SIVAL(buf,46,0xFFB8E5); /* undocumented - used by NT */
-
- buf += 64;
-
- /* Send a POSITIVE NAME STATUS RESPONSE */
- reply_netbios_packet(p,nmb->header.name_trn_id,
- 0,0,True,
- &nmb->question.question_name,
- nmb->question.question_type,
- nmb->question.question_class,
- 0,
- rdata,PTR_DIFF(buf,rdata));
-}
+ struct name_record *n, *next;
+ for (n = d->namelist; n; n = next)
+ {
+ next = n->next;
+ if (n->source == SELF)
+ {
+ /* get all SELF names removed from the WINS server's database */
+ /* XXXX note: problem occurs if this removes the wrong one! */
-/***************************************************************************
- reply to a name query
- ****************************************************************************/
-static struct name_record *search_for_name(struct nmb_name *question,
- struct in_addr ip, int Time,
- enum name_search search)
-{
- int name_type = question->name_type;
- char *qname = question->name;
- BOOL dns_type = name_type == 0x20 || name_type == 0;
-
- struct name_record *n;
-
- DEBUG(3,("Search for %s from %s - ", namestr(question), inet_ntoa(ip)));
-
- /* first look up name in cache. use ip as well as name to locate it */
- n = find_name_search(question,search,ip);
-
- /* now try DNS lookup. */
- if (!n)
- {
- struct in_addr dns_ip;
- unsigned long a;
-
- /* only do DNS lookups if the query is for type 0x20 or type 0x0 */
- if (!dns_type)
- {
- DEBUG(3,("types 0x20 0x1b 0x0 only: name not found\n"));
- return NULL;
- }
-
- /* look it up with DNS */
- a = interpret_addr(qname);
-
- putip((char *)&dns_ip,(char *)&a);
-
- if (!a)
- {
- /* no luck with DNS. We could possibly recurse here XXXX */
- /* if this isn't a bcast then we should send a negative reply XXXX */
- DEBUG(3,("no recursion\n"));
- add_netbios_entry(qname,name_type,NB_ACTIVE,60*60,DNSFAIL,dns_ip,True);
- return NULL;
+ remove_name_entry(d,n->name.name, n->name.name_type);
+ }
+ }
}
-
- /* add it to our cache of names. give it 2 hours in the cache */
- n = add_netbios_entry(qname,name_type,NB_ACTIVE,2*60*60,DNS,dns_ip,True);
-
- /* failed to add it? yikes! */
- if (!n) return NULL;
- }
-
- /* is our entry already dead? */
- if (n->death_time)
- {
- if (n->death_time < Time) return False;
- }
-
- /* it may have been an earlier failure */
- if (n->source == DNSFAIL)
- {
- DEBUG(3,("DNSFAIL\n"));
- return NULL;
- }
-
- DEBUG(3,("OK %s\n",inet_ntoa(n->ip)));
-
- return n;
}
-
-/***************************************************************************
- reply to a name query
- ****************************************************************************/
-void reply_name_query(struct packet_struct *p)
+/*******************************************************************
+ refresh my own names
+ ******************************************************************/
+void refresh_my_names(time_t t)
{
- struct nmb_packet *nmb = &p->packet.nmb;
- struct nmb_name *question = &nmb->question.question_name;
- int name_type = question->name_type;
- BOOL dns_type = name_type == 0x20 || name_type == 0;
- BOOL bcast = nmb->header.nm_flags.bcast;
- int ttl=0;
- int rcode = 0;
- int nb_flags = 0;
- struct in_addr retip;
- char rdata[6];
- BOOL success = True;
- struct name_record *n;
- enum name_search search = (dns_type || name_type == 0x1b) ?
- FIND_GLOBAL : FIND_SELF;
+ struct subnet_record *d;
- DEBUG(3,("Name query "));
-
- if ((n = search_for_name(question,p->ip,p->timestamp, search)))
- {
- /* don't respond to broadcast queries unless the query is for
- a name we own or it is for a Primary Domain Controller name */
- if (bcast && n->source != SELF && name_type != 0x1b)
- {
- if (!lp_wins_proxy() || same_net(p->ip,n->ip,*iface_nmask(p->ip))) {
- /* never reply with a negative response to broadcast queries */
- return;
- }
- }
-
- /* name is directed query, or it's self, or it's a PDC type name */
- ttl = n->death_time - p->timestamp;
- retip = n->ip;
- nb_flags = n->nb_flags;
- }
- else
- {
- if (bcast) return; /* never reply negative response to bcasts */
- success = False;
- }
-
- /* if the IP is 0 then substitute my IP */
- if (zero_ip(retip)) retip = *iface_ip(p->ip);
-
- if (success)
- {
- rcode = 0;
- DEBUG(3,("OK %s\n",inet_ntoa(retip)));
- }
- else
- {
- rcode = 3;
- DEBUG(3,("UNKNOWN\n"));
- }
-
- if (success)
+ for (d = subnetlist; d; d = d->next)
+ {
+ struct name_record *n;
+
+ for (n = d->namelist; n; n = n->next)
{
- rdata[0] = nb_flags;
- rdata[1] = 0;
- putip(&rdata[2],(char *)&retip);
+ /* each SELF name has an individual time to be refreshed */
+ if (n->source == SELF && n->refresh_time < time(NULL) &&
+ n->death_time != 0)
+ {
+ add_my_name_entry(d,n->name.name,n->name.name_type,n->nb_flags);
+ }
}
-
- reply_netbios_packet(p,nmb->header.name_trn_id,
- rcode,0,True,
- &nmb->question.question_name,
- nmb->question.question_type,
- nmb->question.question_class,
- ttl,
- rdata, success ? 6 : 0);
+ }
}
+/*******************************************************************
+ queries names occasionally. an over-cautious, non-trusting WINS server!
-/****************************************************************************
-response from a name query
-****************************************************************************/
-static void response_netbios_packet(struct packet_struct *p)
+ this function has been added because nmbd could be restarted. it
+ is generally a good idea to check all the names that have been
+ reloaded from file.
+
+ XXXX which names to poll and which not can be refined at a later date.
+ ******************************************************************/
+void query_refresh_names(void)
{
- struct nmb_packet *nmb = &p->packet.nmb;
- struct nmb_name *question = &nmb->question.question_name;
- char *qname = question->name;
- BOOL bcast = nmb->header.nm_flags.bcast;
- struct name_response_record *n;
+ struct name_record *n;
+ struct subnet_record *d = find_subnet(ipgrp);
- if (nmb->answers == NULL)
- {
- DEBUG(3,("NMB packet response from %s (bcast=%s) - UNKNOWN\n",
- inet_ntoa(p->ip),
- BOOLSTR(bcast)));
- return;
- }
-
- if (nmb->answers->rr_type == NMB_STATUS) {
- DEBUG(3,("Name status "));
- }
+ static time_t lasttime = 0;
+ time_t t = time(NULL);
- if (nmb->answers->rr_type == NMB_QUERY) {
- DEBUG(3,("Name query "));
- }
+ int count = 0;
+ int name_refresh_time = NAME_POLL_REFRESH_TIME;
+ int max_count = name_refresh_time * 2 / NAME_POLL_INTERVAL;
+ if (max_count > 10) max_count = 10;
- if (nmb->answers->rr_type == NMB_REG) {
- DEBUG(3,("Name registration "));
- }
+ name_refresh_time = NAME_POLL_INTERVAL * max_count / 2;
- if (nmb->answers->rr_type == NMB_REL) {
- DEBUG(3,("Name release "));
- }
+ /* if (!lp_poll_wins()) return; polling of registered names allowed */
- DEBUG(3,("response for %s from %s (bcast=%s)\n",
- namestr(&nmb->answers->rr_name),
- inet_ntoa(p->ip),
- BOOLSTR(bcast)));
-
- if (!(n = find_name_query(nmb->header.name_trn_id))) {
- DEBUG(3,("unknown response (received too late or from nmblookup?)\n"));
- return;
- }
+ if (!d) return;
- n->num_msgs++; /* count number of responses received */
+ if (!lasttime) lasttime = t;
+ if (t - lasttime < NAME_POLL_INTERVAL) return;
- switch (n->cmd_type)
- {
- case MASTER_SERVER_CHECK : DEBUG(4,("MASTER_SVR_CHECK\n")); break;
- case SERVER_CHECK : DEBUG(4,("SERVER_CHECK\n")); break;
- case FIND_MASTER : DEBUG(4,("FIND_MASTER\n")); break;
- case NAME_STATUS_MASTER_CHECK: DEBUG(4,("NAME_STAT_MST_CHK\n")); break;
- case NAME_STATUS_CHECK : DEBUG(4,("NAME_STATUS_CHECK\n")); break;
- case CHECK_MASTER : DEBUG(4,("CHECK_MASTER\n")); break;
- case NAME_CONFIRM_QUERY : DEBUG(4,("NAME_CONFIRM_QUERY\n")); break;
- default: break;
- }
- switch (n->cmd_type)
- {
- case MASTER_SERVER_CHECK:
- case SERVER_CHECK:
- case FIND_MASTER:
- {
- if (nmb->answers->rr_type == NMB_QUERY)
- {
- enum cmd_type cmd = (n->cmd_type == MASTER_SERVER_CHECK) ?
- NAME_STATUS_MASTER_CHECK :
- NAME_STATUS_CHECK;
- if (n->num_msgs > 1 && !strequal(qname,n->name.name))
- {
- /* one subnet, one master browser per workgroup */
- /* XXXX force an election? */
- DEBUG(1,("more than one master browser replied!\n"));
- }
-
- /* initiate a name status check on the server that replied */
- queue_netbios_packet(ClientNMB,NMB_STATUS, cmd,
- nmb->answers->rr_name.name,
- nmb->answers->rr_name.name_type,0,
- False,False,n->to_ip);
- }
- else
- {
- DEBUG(1,("Name query reply has wrong answer rr_type\n"));
- }
- break;
- }
-
- case NAME_STATUS_MASTER_CHECK:
- case NAME_STATUS_CHECK:
- {
- if (nmb->answers->rr_type == NMB_STATUS)
- {
- /* NMB_STATUS arrives: contains the workgroup name
- and server name we require */
- struct nmb_name name;
- fstring serv_name;
-
- if (interpret_node_status(nmb->answers->rdata,
- &name,0x1d,serv_name,p->ip))
- {
- if (*serv_name)
- {
- sync_server(n->cmd_type,serv_name,
- name.name,name.name_type,
- n->to_ip);
- }
- }
- else
- {
- DEBUG(1,("No 0x1d name type in interpret_node_status()\n"));
- }
- }
- else
- {
- DEBUG(1,("Name status reply has wrong answer rr_type\n"));
- }
- break;
- }
-
- case CHECK_MASTER:
- {
- /* no action required here. it's when NO responses are received
- that we need to do something (see expire_name_query_entries) */
-
- DEBUG(4, ("Master browser exists for %s at %s\n",
- namestr(&n->name),
- inet_ntoa(n->to_ip)));
- if (n->num_msgs > 1)
- {
- DEBUG(1,("more than one master browser!\n"));
- }
- if (nmb->answers->rr_type != NMB_QUERY)
- {
- DEBUG(1,("Name query reply has wrong answer rr_type\n"));
- }
- break;
- }
- case NAME_CONFIRM_QUERY:
- {
- DEBUG(4, ("Name query at WINS server: %s at %s - ",
- namestr(&n->name),
- inet_ntoa(n->to_ip)));
- if (nmb->header.rcode == 0 && nmb->answers->rdata)
- {
- int nb_flags = nmb->answers->rdata[0];
- struct in_addr found_ip;
- putip((char*)&found_ip,&nmb->answers->rdata[2]);
-
- DEBUG(4, (" OK: %s\n", inet_ntoa(found_ip)));
- add_netbios_entry(nmb->answers->rr_name.name,
- nmb->answers->rr_name.name_type,
- nb_flags,GET_TTL(0),STATUS_QUERY,found_ip,False);
- }
- else
- {
- DEBUG(4, (" NEGATIVE RESPONSE\n"));
- }
-
- break;
- }
- default:
- {
- DEBUG(0,("unknown command received in response_netbios_packet\n"));
- break;
- }
- }
-}
+ lasttime = time(NULL);
+ for (n = d->namelist; n; n = n->next)
+ {
+ /* only do unique, registered names */
-/****************************************************************************
- process a nmb packet
- ****************************************************************************/
-void process_nmb(struct packet_struct *p)
-{
- struct nmb_packet *nmb = &p->packet.nmb;
-
- debug_nmb_packet(p);
+ if (n->source != REGISTER) continue;
+ if (!NAME_GROUP(n->nb_flags)) continue;
- switch (nmb->header.opcode)
- {
- case 5:
- case 8:
- case 9:
- {
- if (nmb->header.qdcount==0 || nmb->header.arcount==0) break;
- if (nmb->header.response)
- response_name_reg(p);
- else
- reply_name_reg(p);
- break;
- }
-
- case 0:
- {
- if (nmb->header.response)
- {
- switch (nmb->question.question_type)
- {
- case 0x0:
+ if (n->refresh_time < t)
{
- response_netbios_packet(p);
- break;
+ DEBUG(3,("Polling name %s\n", namestr(&n->name)));
+
+ queue_netbios_packet(d,ClientNMB,NMB_QUERY,NAME_QUERY_CONFIRM,
+ n->name.name, n->name.name_type,
+ 0,0,
+ False,False,n->ip,n->ip);
+ count++;
}
- }
- return;
- }
- else if (nmb->header.qdcount>0)
- {
- switch (nmb->question.question_type)
- {
- case NMB_QUERY:
- {
- reply_name_query(p);
- break;
- }
- case NMB_STATUS:
+
+ if (count >= max_count)
{
- reply_name_status(p);
- break;
+ /* don't do too many of these at once, but do enough to
+ cover everyone in the list */
+ return;
}
- }
- return;
- }
- break;
- }
-
- case 6:
- {
- if (nmb->header.qdcount==0 || nmb->header.arcount==0)
- {
- DEBUG(2,("netbios release packet rejected\n"));
- break;
- }
-
- if (nmb->header.response)
- response_name_release(p);
- else
- reply_name_release(p);
- break;
- }
- }
+
+ /* this name will be checked on again, if it's not removed */
+ n->refresh_time += name_refresh_time;
+ }
}
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/nameserv.doc samba-1.9.16alpha11/source/nameserv.doc
--- samba-1.9.16alpha10/source/nameserv.doc Thu Jan 1 10:00:00 1970
+++ samba-1.9.16alpha11/source/nameserv.doc Thu Jul 11 04:48:28 1996
@@ -0,0 +1,132 @@
+this module deals with general maintenance of NetBIOS names.
+
+/*************************************************************************
+ query_refresh_names()
+ *************************************************************************/
+
+this function is responsible for polling all names registered in the
+WINS database. it is planned to enable this function should samba
+detect an inconsistency on the network, which could occur if the
+samba NetBIOS daemon dies and is restarted.
+
+polling is done very infrequently, but all names will be covered
+within a period NAME_POLL_REFRESH_TIME. a group of at most ten names
+will be queried at once, at intervals of NAME_POLL_INTERVAL seconds.
+if the total number of names queried in this way will take too long,
+then the time that an individual name will next be polled is
+increased accordingly.
+
+name query polling is functionality over-and-above the normal
+requirement (see rfc1001.txt 15.1.7 point 7). it is normally the
+responsibility of the owner of a name to re-register the name at
+regular intervals.
+
+
+/*************************************************************************
+ refresh_my_names()
+ *************************************************************************/
+
+this function is responsible for refreshing samba's names that have
+been registered with other servers on a local subnet, or with another
+WINS server if samba is using one.
+
+samba's names' refresh_time will be updated through the use of the function
+add_my_name_entry().
+
+
+/*************************************************************************
+ remove_my_names()
+ *************************************************************************/
+
+this function is responsible for removing all samba's SELF names. it
+is used when samba receives a SIG_TERM. samba at present does not wait
+for the WINS server to reply to the name releases sent out.
+
+
+/*************************************************************************
+ add_my_names()
+ *************************************************************************/
+
+this function is responsible for adding and registering if necessary all
+samba's SELF names, on each of its local subnets and with another WINS
+server if samba is using one.
+
+/*************************************************************************
+ add_my_name_entry()
+ *************************************************************************/
+
+this function is responsible for registering or re-registering one of
+samba's names, either on the local subnet or with another WINS server
+if samba is using one.
+
+if the name is already in samba's database, then it is re-registered,
+otherwise it is simply registered.
+
+if the name is being registered in a WINS capacity (the subnet to which
+the name should be added is the WINS pseudo-subnet) then we add the entry
+immediately if samba is a WINS server. it uses name_register_work()
+because if the name is being added as part of becoming a master browser,
+we want to carry on that process. if the name is registered with another
+WINS server, we must wait for an answer from that WINS server. either
+name_register_work() or name_unregister_work() will be called as a result.
+
+if the name is being registered on a local subnet, then it is
+broadcast. an explicit rejection from another host will result
+in name_unregister_work() being called. no response will, after
+retrying, result in name_register_work() being called.
+
+what ever method is used, the name will either be registered
+or rejected, and what ever process was taking place (becoming
+a master browser for example) will carry on.
+
+expire_netbios_response_entries() is responsible for taking further
+action if no response to the registration is received.
+
+note that there may be a large number of function calls on the
+stack if become_master() is called and samba is configured as
+a WINS server. the loop will be:
+
+become_master(), add_my_name_entry(), name_register_work() and
+back to become_master() with the new value of the workgroup
+'state'.
+
+
+/*************************************************************************
+ remove_name_entry()
+ *************************************************************************/
+
+this function is responsible for removing a NetBIOS name. if the name
+being removed is registered on a local subnet, a name release should be
+broadcast on the local subnet.
+
+if the name is being released in a WINS capacity (the subnet to
+which the name should be added is the WINS pseudo-subnet) then we
+remove the entry immediately if samba is a WINS server. it uses
+name_unregister_work() because if the name is being added as part of
+becoming a master browser, we want to terminate that process. if the
+name is released from another WINS server, we must wait for an
+answer from that WINS server. name_unregister_work() will
+definitely be called as a result, because at present we ignore
+negative responses for a name release from a WINS server.
+
+if the name is being releasedd on a local subnet, then it is
+broadcast. name_unregister_work() will definitely be called
+because we ignore negative name releases at present.
+
+what ever method is used, the name will be released. (NOT TRUE!
+see response_name_release())
+
+expire_netbios_response_entries() is responsible for taking further action
+if no response to the name release is received.
+
+
+/*************************************************************************
+ load_netbios_names()
+ *************************************************************************/
+
+this function is responsible for loading any NetBIOS names that samba,
+in its WINS capacity, has written out to disk. all the relevant details
+are recorded in this file, including the time-to-live. should the
+time left to live be small, the name is not added back in to samba's
+WINS database.
+
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/nameserv.h samba-1.9.16alpha11/source/nameserv.h
--- samba-1.9.16alpha10/source/nameserv.h Mon Jun 10 15:18:56 1996
+++ samba-1.9.16alpha11/source/nameserv.h Thu Jul 18 20:53:15 1996
@@ -20,18 +20,29 @@
*/
+#define GET_TTL(ttl) ((ttl)?MIN(ttl,lp_max_ttl()):lp_max_ttl())
+
/* NTAS uses 2, NT uses 1, WfWg uses 0 */
#define MAINTAIN_LIST 2
#define ELECTION_VERSION 1
-#define MAX_DGRAM_SIZE (80*18+64)
+#define MAX_DGRAM_SIZE (576) /* tcp/ip datagram limit is 576 bytes */
#define MIN_DGRAM_SIZE 12
#define NMB_QUERY 0x20
#define NMB_STATUS 0x21
-#define NMB_REG 0x05
-#define NMB_REL 0x06
+#define NMB_REG 0x05 /* see rfc1002.txt 4.2.2,3,5,6,7,8 */
+#define NMB_REG_REFRESH 0x09 /* see rfc1002.txt 4.2.4 */
+#define NMB_REL 0x06 /* see rfc1002.txt 4.2.9,10,11 */
+#define NMB_WAIT_ACK 0x07 /* see rfc1002.txt 4.2.16 */
+/* XXXX what about all the other types?? 0x1, 0x2, 0x3, 0x4, 0x8? */
+
+#define FIND_SELF 0x01
+#define FIND_WINS 0x02
+#define FIND_LOCAL 0x04
+
+/* NetBIOS flags */
#define NB_GROUP 0x80
#define NB_PERM 0x02
#define NB_ACTIVE 0x04
@@ -44,7 +55,10 @@
#define NB_FLGMSK 0x60
#define REFRESH_TIME (15*60)
+#define NAME_POLL_REFRESH_TIME (5*60)
+#define NAME_POLL_INTERVAL 15
+/* NetBIOS flag identifier */
#define NAME_PERMANENT(p) ((p) & NB_PERM)
#define NAME_ACTIVE(p) ((p) & NB_ACTIVE)
#define NAME_CONFLICT(p) ((p) & NB_CONFL)
@@ -56,23 +70,46 @@
#define NAME_MFLAG(p) (((p) & NB_FLGMSK) == NB_MFLAG)
#define NAME__FLAG(p) (((p) & NB_FLGMSK) == NB__FLAG)
+/* server type identifiers */
+#define AM_MASTER(work) (work->ServerType & SV_TYPE_MASTER_BROWSER)
+#define AM_BACKUP(work) (work->ServerType & SV_TYPE_BACKUP_BROWSER)
+#define AM_DOMCTL(work) (work->ServerType & SV_TYPE_DOMAIN_CTRL)
+
+/* microsoft browser NetBIOS name */
#define MSBROWSE "\001\002__MSBROWSE__\002"
-enum name_search { FIND_SELF, FIND_GLOBAL };
+/* mail slots */
+#define BROWSE_MAILSLOT "\\MAILSLOT\\BROWSE"
+#define NET_LOGON_MAILSLOT "\\MAILSLOT\\NET\\NETLOGON"
+
enum name_source {STATUS_QUERY, LMHOSTS, REGISTER, SELF, DNS, DNSFAIL};
enum node_type {B_NODE=0, P_NODE=1, M_NODE=2, NBDD_NODE=3};
enum packet_type {NMB_PACKET, DGRAM_PACKET};
-enum cmd_type
+enum master_state
{
- NAME_STATUS_MASTER_CHECK,
- NAME_STATUS_CHECK,
- MASTER_SERVER_CHECK,
- SERVER_CHECK,
- FIND_MASTER,
- CHECK_MASTER,
+ MST_NONE,
+ MST_WON,
+ MST_MSB,
+ MST_BROWSER,
+ MST_DOMAIN_NONE,
+ MST_DOMAIN_MEM,
+ MST_DOMAIN_TST,
+ MST_DOMAIN
+};
+
+enum state_type
+{
+ NAME_STATUS_PDC_SRV_CHK,
+ NAME_STATUS_SRV_CHK,
+ NAME_REGISTER_CHALLENGE,
NAME_REGISTER,
NAME_RELEASE,
- NAME_CONFIRM_QUERY
+ NAME_QUERY_CONFIRM,
+ NAME_QUERY_SYNC,
+ NAME_QUERY_PDC_SRV_CHK,
+ NAME_QUERY_SRV_CHK,
+ NAME_QUERY_FIND_MST,
+ NAME_QUERY_MST_CHK
};
/* a netbios name structure */
@@ -87,11 +124,15 @@
{
struct name_record *next;
struct name_record *prev;
- struct nmb_name name;
- time_t death_time;
- struct in_addr ip;
- int nb_flags;
- enum name_source source;
+
+ struct nmb_name name; /* the netbios name */
+ struct in_addr ip; /* ip address of host that owns this name */
+ int nb_flags; /* netbios flags */
+
+ enum name_source source; /* where the name came from */
+
+ time_t death_time; /* time record must be removed (do not remove if 0) */
+ time_t refresh_time; /* time record should be refreshed */
};
/* browse and backup server cache for synchronising browse list */
@@ -127,6 +168,9 @@
struct server_record *serverlist;
+ /* stage of development from non-master to master browser / domain master */
+ enum master_state state;
+
/* work group info */
fstring work_group;
int token; /* used when communicating with backup browsers */
@@ -137,6 +181,7 @@
int announce_interval;
BOOL needannounce;
+
/* election info */
BOOL RunningElection;
BOOL needelection;
@@ -144,13 +189,64 @@
uint32 ElectionCriterion;
};
-/* a subnet structure. it contains a list of workgroups */
+/* initiated name queries recorded in this list to track any responses... */
+struct response_record
+{
+ struct response_record *next;
+ struct response_record *prev;
+
+ uint16 response_id;
+ enum state_type state;
+
+ int fd;
+ int quest_type;
+ struct nmb_name name;
+ int nb_flags;
+ time_t ttl;
+
+ BOOL bcast;
+ BOOL recurse;
+ struct in_addr send_ip;
+ struct in_addr reply_to_ip;
+
+ int num_msgs;
+
+ time_t repeat_time;
+ time_t repeat_interval;
+ int repeat_count;
+};
+
+/* a subnet structure. it contains a list of workgroups and netbios names*/
+
+/* note that a subnet of 255.255.255.255 contains all the WINS netbios names.
+ all communication from such nodes are on a non-broadcast basis: they
+ are point-to-point (P nodes) or mixed point-to-point and broadcast
+ (M nodes). M nodes use point-to-point as a preference, and will use
+ broadcasting for certain activities, or will resort to broadcasting as a
+ last resort, if the WINS server fails (users of wfwg will notice that their
+ machine often freezes for 30 seconds at a time intermittently, if the WINS
+ server is down).
+
+ B nodes will have their own, totally separate subnet record, with their
+ own netbios name set. these do NOT interact with other subnet records'
+ netbios names, INCLUDING the WINS one (with an ip "address", so called,
+ of 255.255.255.255)
+
+ there is a separate response list for each subnet record. in the case of
+ the 255.255.255.255 subnet record (WINS), the WINS server will be able to
+ use this to poll (infrequently!) each of its entries, to ensure that the
+ names are still in use.
+ XXXX this polling is a planned feature for a really over-cautious WINS server
+*/
+
struct subnet_record
{
struct subnet_record *next;
struct subnet_record *prev;
- struct work_record *workgrouplist;
+ struct work_record *workgrouplist; /* list of workgroups */
+ struct name_record *namelist; /* list of netbios names */
+ struct response_record *responselist; /* list of responses expected */
struct in_addr bcast_ip;
struct in_addr mask_ip;
@@ -202,25 +298,6 @@
};
-/* initiated name queries recorded in this list to track any responses... */
-struct name_response_record
-{
- struct name_response_record *next;
- struct name_response_record *prev;
-
- uint16 response_id;
- enum cmd_type cmd_type;
-
- int fd;
- struct nmb_name name;
- BOOL bcast;
- BOOL recurse;
- struct in_addr to_ip;
-
- time_t start_time;
- int num_msgs;
-};
-
/* a datagram - this normally contains SMB data in the data[] array */
struct dgram_packet {
struct {
@@ -258,11 +335,6 @@
struct dgram_packet dgram;
} packet;
};
-
-
-#define AM_MASTER(work) (work->ServerType & SV_TYPE_MASTER_BROWSER)
-#define AM_BACKUP(work) (work->ServerType & SV_TYPE_BACKUP_BROWSER)
-#define AM_DOMCTL(work) (work->ServerType & SV_TYPE_DOMAIN_CTRL)
/* ids for netbios packet types */
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/nameservreply.c samba-1.9.16alpha11/source/nameservreply.c
--- samba-1.9.16alpha10/source/nameservreply.c Thu Jan 1 10:00:00 1970
+++ samba-1.9.16alpha11/source/nameservreply.c Thu Jul 18 20:53:16 1996
@@ -0,0 +1,552 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1996
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Module name: nameservreply.c
+
+ Revision History:
+
+ 14 jan 96: lkcl@pires.co.uk
+ added multiple workgroup domain master support
+
+ 04 jul 96: lkcl@pires.co.uk
+ created module nameservreply containing NetBIOS reply functions
+
+*/
+
+#include "includes.h"
+
+extern int ClientNMB;
+
+extern int DEBUGLEVEL;
+
+extern struct in_addr ipgrp;
+
+
+/****************************************************************************
+ add a netbios entry. respond to the (possibly new) owner.
+ **************************************************************************/
+void add_name_respond(struct subnet_record *d, int fd, struct in_addr from_ip,
+ uint16 response_id,
+ struct nmb_name *name,
+ int nb_flags, int ttl, struct in_addr register_ip,
+ BOOL new_owner, struct in_addr reply_to_ip)
+{
+ /* register the old or the new owners' ip */
+ add_netbios_entry(d,name->name,name->name_type,
+ nb_flags,ttl,REGISTER,register_ip,False,True);
+
+ /* reply yes or no to the host that requested the name */
+ send_name_response(fd,from_ip, response_id, NMB_REG,
+ new_owner, True,
+ name, nb_flags, ttl, reply_to_ip);
+}
+
+/****************************************************************************
+send a registration / release response: pos/neg
+**************************************************************************/
+void send_name_response(int fd, struct in_addr from_ip,
+ int name_trn_id, int opcode, BOOL success, BOOL recurse,
+ struct nmb_name *reply_name, int nb_flags, int ttl,
+ struct in_addr ip)
+{
+ char rdata[6];
+ struct packet_struct p;
+
+ int rcode = 0;
+
+ if (success == False)
+ {
+ /* NEGATIVE RESPONSE */
+ rcode = 6;
+ }
+ else if (opcode == NMB_REG && recurse == False)
+ {
+ /* END-NODE CHALLENGE REGISTRATION RESPONSE */
+ rcode = 0;
+ }
+
+ rdata[0] = nb_flags;
+ rdata[1] = 0;
+ putip(&rdata[2],(char *)&ip);
+
+ p.ip = from_ip;
+ p.port = NMB_PORT;
+ p.fd = fd;
+ p.timestamp = time(NULL);
+ p.packet_type = NMB_PACKET;
+
+ reply_netbios_packet(&p,name_trn_id,
+ rcode,opcode,opcode,recurse,
+ reply_name, 0x20, 0x1,
+ ttl,
+ rdata, 6);
+}
+
+
+/****************************************************************************
+reply to a name release
+****************************************************************************/
+void reply_name_release(struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct in_addr ip;
+ int nb_flags = nmb->additional->rdata[0];
+ BOOL bcast = nmb->header.nm_flags.bcast;
+ struct name_record *n;
+ struct subnet_record *d = NULL;
+ int search = 0;
+ BOOL success = False;
+
+ putip((char *)&ip,&nmb->additional->rdata[2]);
+
+ DEBUG(3,("Name release on name %s\n",
+ namestr(&nmb->question.question_name)));
+
+ if (!(d = find_req_subnet(p->ip, bcast)))
+ {
+ DEBUG(3,("response packet: bcast %s not known\n",
+ inet_ntoa(p->ip)));
+ return;
+ }
+
+ if (bcast)
+ search &= FIND_LOCAL;
+ else
+ search &= FIND_WINS;
+
+ n = find_name_search(&d, &nmb->question.question_name,
+ search, ip);
+
+ /* XXXX under what conditions should we reject the removal?? */
+ if (n && n->nb_flags == nb_flags)
+ {
+ success = True;
+
+ remove_name(d,n);
+ n = NULL;
+ }
+
+ if (bcast) return;
+
+ /* Send a NAME RELEASE RESPONSE (pos/neg) see rfc1002.txt 4.2.10-11 */
+ send_name_response(p->fd,p->ip, nmb->header.name_trn_id, NMB_REL,
+ success, False,
+ &nmb->question.question_name, nb_flags, 0, ip);
+}
+
+
+/****************************************************************************
+reply to a reg request
+**************************************************************************/
+void reply_name_reg(struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct nmb_name *question = &nmb->question.question_name;
+
+ struct nmb_name *reply_name = question;
+
+ char *qname = question->name;
+ int qname_type = question->name_type;
+
+ BOOL bcast = nmb->header.nm_flags.bcast;
+
+ int ttl = GET_TTL(nmb->additional->ttl);
+ int nb_flags = nmb->additional->rdata[0];
+ BOOL group = NAME_GROUP(nb_flags);
+
+ struct subnet_record *d = NULL;
+ struct name_record *n = NULL;
+
+ BOOL success = True;
+ BOOL secured_redirect = False;
+
+ struct in_addr ip, from_ip;
+ int search = 0;
+
+ putip((char *)&from_ip,&nmb->additional->rdata[2]);
+ ip = from_ip;
+
+ DEBUG(3,("Name registration for name %s at %s\n",
+ namestr(question),inet_ntoa(ip)));
+
+ if (group)
+ {
+ /* apparently we should return 255.255.255.255 for group queries
+ (email from MS) */
+ ip = ipgrp;
+ }
+
+ if (!(d = find_req_subnet(p->ip, bcast)))
+ {
+ DEBUG(3,("response packet: bcast %s not known\n",
+ inet_ntoa(p->ip)));
+ return;
+ }
+
+ if (bcast)
+ search &= FIND_LOCAL;
+ else
+ search &= FIND_WINS;
+
+ /* see if the name already exists */
+ n = find_name_search(&d, question, search, from_ip);
+
+ if (n)
+ {
+ if (!group) /* unique names */
+ {
+ if (n->source == SELF || NAME_GROUP(n->nb_flags))
+ {
+ /* no-one can register one of samba's names, nor can they
+ register a name that's a group name as a unique name */
+
+ success = False;
+ }
+ else if(!ip_equal(ip, n->ip))
+ {
+ /* XXXX rfc1001.txt says:
+ * if we are doing secured WINS, we must send a Wait-Acknowledge
+ * packet (WACK) to the person who wants the name, then do a
+ * name query on the person who currently owns the unique name.
+ * if the current owner still says they own it, the person who wants
+ * the name can't have it. if they do not, or are not alive, they can.
+ */
+
+ secured_redirect = True;
+
+ reply_name = &n->name;
+ }
+ else
+ {
+ n->ip = ip;
+ n->death_time = ttl?p->timestamp+ttl*3:0;
+ DEBUG(3,("%s owner: %s\n",namestr(&n->name),inet_ntoa(n->ip)));
+ }
+ }
+ else
+ {
+ /* refresh the name */
+ if (n->source != SELF)
+ {
+ n->death_time = ttl?p->timestamp + ttl*3:0;
+ }
+ }
+
+ /* XXXX bug reported by terryt@ren.pc.athabascau.ca */
+ /* names that people have checked for and not found get DNSFAILed.
+ we need to update the name record if someone then registers */
+
+ if (n->source == DNSFAIL)
+ n->source = REGISTER;
+
+ }
+ else
+ {
+ /* add the name to our name/subnet, or WINS, database */
+ n = add_netbios_entry(d,qname,qname_type,nb_flags,ttl,REGISTER,ip,
+ True,!bcast);
+ }
+
+ /* if samba owns a unique name on a subnet, then it must respond and
+ disallow the attempted registration. if the registration is
+ successful by broadcast, only then is there no need to respond
+ (implicit registration: see rfc1001.txt 15.2.1).
+ */
+
+ if (bcast && success) return;
+
+ if (secured_redirect)
+ {
+ char rdata[2];
+
+ /* XXXX luke is confused. RSVAL or SSVAL? assume NMB byte ordering */
+ RSSVAL(rdata,0,(nmb->header.opcode&0xf) + ((nb_flags&0xff) << 4));
+
+ /* XXXX mistake in rfc1002.txt? 4.2.16: NULL is 0xa see 4.2.1.3
+ type = 0x0a; see rfc1002.txt 4.2.1.3
+ class = 0x01; see rfc1002.txt 4.2.16
+ */
+
+ /* send WAIT ACKNOWLEDGEMENT see rfc1002.txt 4.2.16 */
+ reply_netbios_packet(p,nmb->header.name_trn_id,
+ 0,NMB_WAIT_ACK,NMB_WAIT_ACK,False,
+ reply_name, 0x0a, 0x01,
+ 15*1000, /* 15 seconds long enough to wait? */
+ rdata, 2);
+
+ /* initiate some enquiries to the current owner. */
+ queue_netbios_packet(d,ClientNMB,NMB_QUERY,
+ NAME_REGISTER_CHALLENGE,
+ reply_name->name,reply_name->name_type,nb_flags,0,
+ False, False, n->ip, p->ip);
+ }
+ else
+ {
+ /* Send a NAME REGISTRATION RESPONSE (pos/neg) see rfc1002.txt 4.2.13-14
+ or an END-NODE CHALLENGE REGISTRATION RESPONSE see rfc1002.txt 4.2.7
+ */
+
+ send_name_response(p->fd,p->ip, nmb->header.name_trn_id, NMB_REG,
+ success, True,
+ reply_name, nb_flags, ttl, ip);
+ }
+}
+
+
+/****************************************************************************
+reply to a name status query
+****************************************************************************/
+void reply_name_status(struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ char *qname = nmb->question.question_name.name;
+ int ques_type = nmb->question.question_name.name_type;
+ char rdata[MAX_DGRAM_SIZE];
+ char *countptr, *buf, *bufend;
+ int names_added;
+ struct name_record *n;
+ struct subnet_record *d = NULL;
+ int search = FIND_SELF;
+
+ BOOL bcast = nmb->header.nm_flags.bcast;
+
+ if (!(d = find_req_subnet(p->ip, bcast)))
+ {
+ DEBUG(3,("Name status req: bcast %s not known\n",
+ inet_ntoa(p->ip)));
+ return;
+ }
+
+ DEBUG(3,("Name status for name %s %s\n",
+ namestr(&nmb->question.question_name), inet_ntoa(p->ip)));
+
+ if (bcast)
+ search |= FIND_WINS;
+ else
+ search |= FIND_LOCAL;
+
+ n = find_name_search(&d, &nmb->question.question_name,
+ search, p->ip);
+
+ if (!n) return;
+
+ /* XXXX hack, we should calculate exactly how many will fit */
+ bufend = &rdata[MAX_DGRAM_SIZE] - 18;
+ countptr = buf = rdata;
+ buf += 1;
+
+ names_added = 0;
+
+ for (n = d->namelist ; n && buf < bufend; n = n->next)
+ {
+ int name_type = n->name.name_type;
+
+ if (n->source != SELF) continue;
+
+ /* start with first bit of putting info in buffer: the name */
+
+ bzero(buf,18);
+ sprintf(buf,"%-15.15s",n->name.name);
+ strupper(buf);
+
+ /* now check if we want to exclude other workgroup names
+ from the response. if we don't exclude them, windows clients
+ get confused and will respond with an error for NET VIEW */
+
+ if (name_type >= 0x1b && name_type <= 0x20 &&
+ ques_type >= 0x1b && ques_type <= 0x20)
+ {
+ if (!strequal(qname, n->name.name)) continue;
+ }
+
+ /* carry on putting name info in buffer */
+
+ buf[15] = name_type;
+ buf[16] = n->nb_flags;
+
+ buf += 18;
+
+ names_added++;
+ }
+
+ SCVAL(countptr,0,names_added);
+
+ /* XXXXXXX we should fill in more fields of the statistics structure */
+ bzero(buf,64);
+ {
+ extern int num_good_sends,num_good_receives;
+ SIVAL(buf,20,num_good_sends);
+ SIVAL(buf,24,num_good_receives);
+ }
+
+ SIVAL(buf,46,0xFFB8E5); /* undocumented - used by NT */
+
+ buf += 64;
+
+ /* Send a POSITIVE NAME STATUS RESPONSE */
+ reply_netbios_packet(p,nmb->header.name_trn_id,
+ 0,NMB_STATUS,0,True,
+ &nmb->question.question_name,
+ nmb->question.question_type,
+ nmb->question.question_class,
+ 0,
+ rdata,PTR_DIFF(buf,rdata));
+}
+
+
+/***************************************************************************
+reply to a name query.
+
+with broadcast name queries:
+
+ - only reply if the query is for one of YOUR names. all other machines on
+ the network will be doing the same thing (that is, only replying to a
+ broadcast query if they own it)
+ NOTE: broadcast name queries should only be sent out by a machine
+ if they HAVEN'T been configured to use WINS. this is generally bad news
+ in a wide area tcp/ip network and should be rectified by the systems
+ administrator. USE WINS! :-)
+ - the exception to this is if the query is for a Primary Domain Controller
+ type name (0x1b), in which case, a reply is sent.
+
+ - NEVER send a negative response to a broadcast query. no-one else will!
+
+with directed name queries:
+
+ - if you are the WINS server, you are expected to respond with either
+ a negative response, a positive response, or a wait-for-acknowledgement
+ packet, and then later on a pos/neg response.
+
+****************************************************************************/
+void reply_name_query(struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct nmb_name *question = &nmb->question.question_name;
+ int name_type = question->name_type;
+ BOOL bcast = nmb->header.nm_flags.bcast;
+ int ttl=0;
+ int rcode = 0;
+ int nb_flags = 0;
+ struct in_addr retip;
+ char rdata[6];
+ struct subnet_record *d = NULL;
+ BOOL success = True;
+ struct name_record *n;
+
+ /* directed queries are for WINS server: broadcasts are local SELF queries.
+ the exception is PDC names. */
+
+ int search = bcast ? FIND_LOCAL | FIND_SELF : FIND_WINS;
+
+ if (name_type == 0x1b)
+ {
+ /* even if it's a broadcast, we don't ignore queries for PDC names */
+ search = FIND_WINS;
+ }
+
+ if (search | FIND_LOCAL)
+ {
+ if (!(d = find_req_subnet(p->ip, bcast)))
+ {
+ DEBUG(3,("name query: bcast %s not known\n",
+ inet_ntoa(p->ip)));
+ success = False;
+ }
+ }
+ else
+ {
+ if (!(d = find_subnet(ipgrp)))
+ {
+ DEBUG(3,("name query: wins search %s not known\n",
+ inet_ntoa(p->ip)));
+ success = False;
+ }
+ }
+
+ DEBUG(3,("Name query "));
+
+ if (search == 0)
+ {
+ /* eh? no criterion for searching database. help! */
+ success = False;
+ }
+
+ if (success && (n = search_for_name(&d,question,p->ip,p->timestamp, search)))
+ {
+ /* don't respond to broadcast queries unless the query is for
+ a name we own or it is for a Primary Domain Controller name */
+
+ if (bcast && n->source != SELF && name_type != 0x1b) {
+ if (!lp_wins_proxy() || same_net(p->ip,n->ip,*iface_nmask(p->ip))) {
+ /* never reply with a negative response to broadcast queries */
+ return;
+ }
+ }
+
+ /* name is directed query, or it's self, or it's a PDC type name, or
+ we're replying on behalf of a caller because they are on a different
+ subnet and cannot hear the broadcast. XXXX lp_wins_proxy should be
+ switched off in environments where broadcasts are forwarded */
+
+ /* XXXX note: for proxy servers, we should forward the query on to
+ another WINS server if the name is not in our database, or we are
+ not a WINS server ourselves
+ */
+ ttl = n->death_time ? n->death_time - p->timestamp : GET_TTL(0);
+ retip = n->ip;
+ nb_flags = n->nb_flags;
+ }
+ else
+ {
+ if (bcast) return; /* never reply negative response to bcasts */
+ success = False;
+ }
+
+ /* if the IP is 0 then substitute my IP */
+ if (zero_ip(retip)) retip = *iface_ip(p->ip);
+
+ if (success)
+ {
+ rcode = 0;
+ DEBUG(3,("OK %s\n",inet_ntoa(retip)));
+ }
+ else
+ {
+ rcode = 3;
+ DEBUG(3,("UNKNOWN\n"));
+ }
+
+ if (success)
+ {
+ rdata[0] = nb_flags;
+ rdata[1] = 0;
+ putip(&rdata[2],(char *)&retip);
+ }
+
+ reply_netbios_packet(p,nmb->header.name_trn_id,
+ rcode,NMB_QUERY,0,True,
+ &nmb->question.question_name,
+ nmb->question.question_type,
+ nmb->question.question_class,
+ ttl,
+ rdata, success ? 6 : 0);
+}
+
+
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/nameservreply.doc samba-1.9.16alpha11/source/nameservreply.doc
--- samba-1.9.16alpha10/source/nameservreply.doc Thu Jan 1 10:00:00 1970
+++ samba-1.9.16alpha11/source/nameservreply.doc Thu Jul 11 04:48:28 1996
@@ -0,0 +1,186 @@
+/*************************************************************************
+ reply_name_query()
+ *************************************************************************/
+
+this function is responsible for replying to a NetBIOS name query.
+
+there are two kinds of name queries: directed, and broadcast. directed
+queries are usually sent to samba in its WINS capacity. such hosts are
+termed 'point-to-point' hosts. broadcast queries are usually sent from
+'broadcast' or 'mixed' hosts.
+
+broadcasting is used by either older NetBIOS hosts, new NetBIOS hosts that
+have not had WINS capabilities added and new NetBIOS hosts that think the
+WINS server has died.
+
+the samba NetBIOS name database is divided into sections, on a
+per-subnet basis. there is also a WINS NetBIOS name database, and for
+convenience this is added as a pseudo-subnet with the ip address of
+255.255.255.255.
+
+the local subnet NetBIOS name databases only contain samba's names.
+the reason for this is that if a broadcast query is received, a NetBIOS
+hosts is only expected to respond if that query is for one of its own
+names (the exception to this is if a host is configured as a 'proxy'
+server, in which case, samba should redirect the query to another WINS
+server).
+
+the WINS pseudo-subnet NetBIOS database contains all NetBIOS names
+that are not 'special browser' type names (regarding this i am a
+_bit_ confused :-). names of type 0x01, 0x1d and 0x1e i consider to
+be 'special browser' names. at the moment. maybe.
+
+the type of search to be initiated is determined. if the NetBIOS name
+type is a non-special-browser name, then the WINS database is included
+in the search.
+
+if the name is not a special browser name, then we need to find the
+right subnet that the query came from. this is done using
+find_req_subnet(). this also has the benefit of stopping any queries
+from subnets that samba does not know about.
+
+if the query is a broadcast query, then the database of the local subnet
+is included in the search.
+
+the name is then searched for in the appropriate NetBIOS data structures.
+if it is found, then we need to check whether it is appropriate for us
+to reply to such a query.
+
+we will only reply if the query is a directed query, the name belongs to
+samba on that subnet, or the name is a primary domain controller type,
+or we're doing replies on behalf of hosts on subnets not known to the
+host issuing the query. in the latter instance, it would be appropriate
+if samba is using a WINS server for it to forward the name query on to
+this WINS server.
+
+reply_name_query() then takes note of all the information that is
+needed to construct a reply to the caller. a negative reply (if the
+name is unknown to samba) or a positive reply (the name is known to
+samba) is then issued.
+
+
+/*************************************************************************
+ reply_name_status()
+ *************************************************************************/
+
+this function is responsible for constructing a reply to a NetBIOS
+name status query. this response contains all samba's NetBIOS names
+on the subnet that the query came in from.
+
+a reply will only be made if the NetBIOS name being queried exists.
+
+see rfc1001.txt and rfc1002.txt for details of the name status reply.
+
+
+/*************************************************************************
+ reply_name_reg()
+ *************************************************************************/
+
+this function is responsible for updating the NetBIOS name database
+from registration packets sent out by hosts wishing to register a
+name, and for informing them, if necessary, if this is acceptable
+or not.
+
+name registration can be done by broadcast or by point-to-point,
+i.e the registration is sent directly to samba in its capacity as
+a WINS server.
+
+if the name registration is done by broadcast (see rfc1001.txt 15.2.1),
+then samba's involvement in replying is limited to whether that name
+is owned by samba or not, on the relevant subnet.
+
+if the name registration is done point-to-point (see rfc1001.txt 15.2.2)
+then samba will first need to check its WINS name database records and
+proceed accordingly.
+
+samba looks for the appropriate subnet record that the registration
+should be added to / checked against, using find_req_subnet().
+
+next, the name is searched for in the local database or the WINS
+database as appropriate.
+
+if the name is not found, then it is added to the NetBIOS name database,
+using add_netbios_entry(), which may choose not to add the name (not
+that this affects the registration of the name on the network in any way).
+it will only add names to the WINS database, and even then it will only
+add non-special-browser type names.
+
+if the name is found, then samba must decide whether to accept the name
+or not. a group name is always added. for unique names, further checks
+need to be carried out.
+
+firstly, if the name in the database is one of samba's names, or if the
+name in the database is a group name, then it cannot be added as a unique
+name belonging to someone else. it is therefore rejected.
+
+secondly, if the ip address of the name being registered does not match
+against the ip in the database, then the unique name may belong to
+someone else. a check needs to be carried out with the owner in case
+they still wish to keep this name. a detailed discussion of what action
+to take is in rfc1001.txt 15.2.2.2 and 15.2.2.3.
+
+samba currently implements non-secured WINS, whereupon the responsibility
+for checking the name is passed on to the host doing the registration.
+rfc1001.txt refers to this as an END-NODE CHALLENGE REGISTRATION RESPONSE.
+(samba itself cannot yet cope with receiving such responses if it
+registers its names with another WINS server).
+
+having decided what kind of response to send (if any - acceptance of
+name registrations by broadcast is implicit), samba will send either a
+positive or negative NAME REGISTRATION RESPONSE, or an END-NODE CHALLENGE
+REGISTRATION RESPONSE to the host that initially sent the registration.
+
+whew.
+
+
+/*************************************************************************
+ reply_name_release()
+ *************************************************************************/
+
+this function is responsible for removing a NetBIOS name from the
+database when a server sends a release packet.
+
+samba looks for the appropriate subnet record that the release should
+be removed from, using find_req_subnet(). next, the name is searched
+for in the local database or the WINS database as appropriate.
+
+if the name is found, it is removed from the database and a
+positive reply is sent confirming this. if the name is not
+found, a negative reply is sent.
+
+a reply is _not_ sent if the release was done by broadcast: the
+release is implicit, and we should be grateful that they bothered
+to tell us. if the release was done by directed packet, then
+we deal with it as a WINS server and must reply (pos / neg).
+
+at present, the criteria for removing a name have yet to be
+developed / experimented with. at present, the only flags that
+are checked are the NetBIOS flags.
+
+
+/*************************************************************************
+ send_name_response()
+ *************************************************************************/
+
+this function is a wrap around reply_netbios_packet(). it sends
+a response to a name registration or release packet, minimising
+the function parameters needed to do this.
+
+if the function is called with the parameter 'success' set to
+True, then a positive response (to the registration or release)
+is made (see rfc1002.txt 4.2.5 and 4.2.10). if this parameter
+is False, then a negative response is issued (see rfc1002.txt
+4.2.6 and 4.2.11)
+
+if the function is called with a registration code, and the
+parameter 'recurse' is False, then an End-Node Challenge
+Registration response is issued (see rfc1002.txt 4.2.7)
+
+note: this function could also easily be used for name conflict
+demand (see rfc1002.txt 4.2.8).
+
+note: End-Node Challenge Registration response is only sent in
+non-secured NetBIOS Name Server implementations. samba now
+implements secured NetBIOS Name Server functionality (see
+rfc1001.txt 15.1.6).
+
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/nameservresp.c samba-1.9.16alpha11/source/nameservresp.c
--- samba-1.9.16alpha10/source/nameservresp.c Thu Jan 1 10:00:00 1970
+++ samba-1.9.16alpha11/source/nameservresp.c Thu Jul 18 20:53:16 1996
@@ -0,0 +1,743 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1996
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Revision History:
+
+ Module name: nameservresp.c
+
+ 14 jan 96: lkcl@pires.co.uk
+ added multiple workgroup domain master support
+
+ 05 jul 96: lkcl@pires.co.uk
+ created module nameservresp containing NetBIOS response functions
+
+*/
+
+#include "includes.h"
+
+extern int ClientNMB;
+
+extern int DEBUGLEVEL;
+
+extern pstring scope;
+extern struct in_addr ipzero;
+
+#define GET_TTL(ttl) ((ttl)?MIN(ttl,lp_max_ttl()):lp_max_ttl())
+
+
+/****************************************************************************
+ response for a reg release received. samba has asked a WINS server if it
+ could release a name.
+ **************************************************************************/
+static void response_name_release(struct subnet_record *d,
+ struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ char *name = nmb->question.question_name.name;
+ int type = nmb->question.question_name.name_type;
+
+ DEBUG(4,("response name release received\n"));
+
+ if (nmb->header.rcode == 0 && nmb->answers->rdata)
+ {
+ /* IMPORTANT: see expire_netbios_response_entries() */
+
+ struct in_addr found_ip;
+ putip((char*)&found_ip,&nmb->answers->rdata[2]);
+
+ /* NOTE: we only release our own names at present */
+ if (ismyip(found_ip))
+ {
+ name_unregister_work(d,name,type);
+ }
+ else
+ {
+ DEBUG(2,("name release for different ip! %s %s\n",
+ inet_ntoa(found_ip),
+ namestr(&nmb->question.question_name)));
+ }
+ }
+ else
+ {
+ DEBUG(2,("name release for %s rejected!\n",
+ namestr(&nmb->question.question_name)));
+
+ /* XXXX PANIC! what to do if it's one of samba's own names? */
+
+ /* XXXX do we honestly care if our name release was rejected?
+ only if samba is issuing the release on behalf of some out-of-sync
+ server. if it's one of samba's SELF names, we don't care. */
+ }
+}
+
+
+/****************************************************************************
+response for a reg request received
+**************************************************************************/
+static void response_name_reg(struct subnet_record *d, struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ char *name = nmb->question.question_name.name;
+ int type = nmb->question.question_name.name_type;
+ BOOL bcast = nmb->header.nm_flags.bcast;
+
+ DEBUG(4,("response name registration received!\n"));
+
+ if (nmb->header.rcode == 0 && nmb->answers->rdata)
+ {
+ /* IMPORTANT: see expire_netbios_response_entries() */
+
+ int nb_flags = nmb->answers->rdata[0];
+ int ttl = nmb->answers->ttl;
+ struct in_addr found_ip;
+
+ putip((char*)&found_ip,&nmb->answers->rdata[2]);
+
+ name_register_work(d,name,type,nb_flags,ttl,found_ip,bcast);
+ }
+ else
+ {
+ DEBUG(1,("name registration for %s rejected!\n",
+ namestr(&nmb->question.question_name)));
+
+ /* oh dear. we have problems. possibly unbecome a master browser. */
+ name_unregister_work(d,name,type);
+ }
+}
+
+
+/****************************************************************************
+ response from a name query server check. states of type NAME_QUERY_PDC_SRV_CHK,
+ NAME_QUERY_SRV_CHK, and NAME_QUERY_FIND_MST dealt with here.
+ ****************************************************************************/
+static void response_server_check(struct nmb_name *ans_name,
+ struct response_record *n, struct subnet_record *d)
+{
+ /* issue another state: this time to do a name status check */
+
+ enum state_type cmd = (n->state == NAME_QUERY_PDC_SRV_CHK) ?
+ NAME_STATUS_PDC_SRV_CHK : NAME_STATUS_SRV_CHK;
+
+ /* initiate a name status check on the server that replied */
+ queue_netbios_packet(d,ClientNMB,NMB_STATUS, cmd,
+ ans_name->name, ans_name->name_type,
+ 0,0,
+ False,False,n->send_ip,n->reply_to_ip);
+}
+
+
+/****************************************************************************
+ interpret a node status response. this is pretty hacked: we need two bits of
+ info. a) the name of the workgroup b) the name of the server. it will also
+ add all the names it finds into the namelist.
+****************************************************************************/
+static BOOL interpret_node_status(struct subnet_record *d,
+ char *p, struct nmb_name *name,int t,
+ char *serv_name, struct in_addr ip, BOOL bcast)
+{
+ int level = t==0x20 ? 4 : 0;
+ int numnames = CVAL(p,0);
+ BOOL found = False;
+
+ DEBUG(level,("received %d names\n",numnames));
+
+ p += 1;
+
+ if (serv_name) *serv_name = 0;
+
+ while (numnames--)
+ {
+ char qname[17];
+ int type;
+ fstring flags;
+ int nb_flags;
+
+ BOOL group = False;
+ BOOL add = False;
+
+ *flags = 0;
+
+ StrnCpy(qname,p,15);
+ type = CVAL(p,15);
+ nb_flags = p[16];
+ trim_string(qname,NULL," ");
+
+ p += 18;
+
+ if (NAME_GROUP (nb_flags)) { strcat(flags,"<GROUP> "); group=True;}
+ if (NAME_BFLAG (nb_flags)) { strcat(flags,"B "); }
+ if (NAME_PFLAG (nb_flags)) { strcat(flags,"P "); }
+ if (NAME_MFLAG (nb_flags)) { strcat(flags,"M "); }
+ if (NAME__FLAG (nb_flags)) { strcat(flags,"_ "); }
+ if (NAME_DEREG (nb_flags)) { strcat(flags,"<DEREGISTERING> "); }
+ if (NAME_CONFLICT (nb_flags)) { strcat(flags,"<CONFLICT> "); add=True;}
+ if (NAME_ACTIVE (nb_flags)) { strcat(flags,"<ACTIVE> "); add=True; }
+ if (NAME_PERMANENT(nb_flags)) { strcat(flags,"<PERMANENT> "); add=True;}
+
+ /* might as well update our namelist while we're at it */
+ if (add)
+ {
+ struct in_addr nameip;
+ enum name_source src;
+
+ if (ismyip(ip)) {
+ nameip = ipzero;
+ src = SELF;
+ } else {
+ nameip = ip;
+ src = STATUS_QUERY;
+ }
+ add_netbios_entry(d,qname,type,nb_flags,2*60*60,src,nameip,True,bcast);
+ }
+
+ /* we want the server name */
+ if (serv_name && !*serv_name && !group && t == 0)
+ {
+ StrnCpy(serv_name,qname,15);
+ serv_name[15] = 0;
+ }
+
+ /* looking for a name and type? */
+ if (name && !found && (t == type))
+ {
+ /* take a guess at some of the name types we're going to ask for.
+ evaluate whether they are group names or no... */
+ if (((t == 0x1b || t == 0x1d ) && !group) ||
+ ((t == 0x20 || t == 0x1c || t == 0x1e) && group))
+ {
+ found = True;
+ make_nmb_name(name,qname,type,scope);
+ }
+ }
+
+ DEBUG(level,("\t%s(0x%x)\t%s\n",qname,type,flags));
+ }
+ DEBUG(level,("num_good_sends=%d num_good_receives=%d\n",
+ IVAL(p,20),IVAL(p,24)));
+ return found;
+}
+
+
+/****************************************************************************
+ response from a name status check. states of type NAME_STATUS_PDC_SRV_CHK
+ and NAME_STATUS_SRV_CHK dealt with here.
+ ****************************************************************************/
+static void response_name_status_check(struct in_addr ip,
+ struct nmb_packet *nmb, BOOL bcast,
+ struct response_record *n, struct subnet_record *d)
+{
+ /* NMB_STATUS arrives: contains workgroup name and server name required.
+ amongst other things. */
+
+ struct nmb_name name;
+ fstring serv_name;
+
+ if (interpret_node_status(d,nmb->answers->rdata,
+ &name,name.name_type,serv_name,ip,bcast))
+ {
+ if (*serv_name)
+ {
+ sync_server(n->state,serv_name,
+ name.name,name.name_type, n->send_ip);
+ }
+ }
+ else
+ {
+ DEBUG(1,("No 0x1d name type in interpret_node_status()\n"));
+ }
+}
+
+
+/****************************************************************************
+ response from a name query for secured WINS registration. a state of
+ NAME_REGISTER_CHALLENGE is dealt with here.
+ ****************************************************************************/
+static void response_name_query_register(struct nmb_packet *nmb,
+ struct nmb_name *ans_name,
+ struct response_record *n, struct subnet_record *d)
+{
+ struct in_addr register_ip;
+ BOOL new_owner;
+
+ DEBUG(4, ("Name query at %s ip %s - ",
+ namestr(&n->name), inet_ntoa(n->send_ip)));
+
+ if (!name_equal(&n->name, ans_name))
+ {
+ /* someone gave us the wrong name as a reply. oops. */
+ /* XXXX should say to them 'oi! release that name!' */
+
+ DEBUG(4,("unexpected name received: %s\n", namestr(ans_name)));
+ return;
+ }
+
+ if (nmb->header.rcode == 0 && nmb->answers->rdata)
+ {
+ /* we had sent out a name query to the current owner
+ of a name because someone else wanted it. now they
+ have responded saying that they still want the name,
+ so the other host can't have it.
+ */
+
+ /* first check all the details are correct */
+
+ int nb_flags = nmb->answers->rdata[0];
+ struct in_addr found_ip;
+
+ putip((char*)&found_ip,&nmb->answers->rdata[2]);
+
+ if (nb_flags != n->nb_flags)
+ {
+ /* someone gave us the wrong nb_flags as a reply. oops. */
+ /* XXXX should say to them 'oi! release that name!' */
+
+ DEBUG(4,("expected nb_flags: %d\n", n->nb_flags));
+ DEBUG(4,("unexpected nb_flags: %d\n", nb_flags));
+ return;
+ }
+
+ if (!ip_equal(n->send_ip, found_ip))
+ {
+ /* someone gave us the wrong ip as a reply. oops. */
+ /* XXXX should say to them 'oi! release that name!' */
+
+ DEBUG(4,("expected ip: %s\n", inet_ntoa(n->send_ip)));
+ DEBUG(4,("unexpected ip: %s\n", inet_ntoa(found_ip)));
+ return;
+ }
+
+ DEBUG(4, (" OK: %s\n", inet_ntoa(found_ip)));
+
+ /* fine: now tell the other host they can't have the name */
+ register_ip = n->send_ip;
+ new_owner = False;
+ }
+ else
+ {
+ DEBUG(4, (" NEGATIVE RESPONSE!\n"));
+
+ /* the owner didn't want the name: the other host can have it */
+ register_ip = n->reply_to_ip;
+ new_owner = True;
+ }
+
+ /* register the old or the new owners' ip */
+ add_name_respond(d, n->fd, d->myip, n->response_id,&n->name,n->nb_flags,
+ GET_TTL(0), register_ip,
+ new_owner, n->reply_to_ip);
+}
+
+
+/****************************************************************************
+ response from a name query to sync browse lists or to update our netbios
+ entry. states of type NAME_QUERY_SYNC and NAME_QUERY_CONFIRM
+ ****************************************************************************/
+static void response_name_query_sync(struct nmb_packet *nmb,
+ struct nmb_name *ans_name, BOOL bcast,
+ struct response_record *n, struct subnet_record *d)
+{
+ DEBUG(4, ("Name query at %s ip %s - ",
+ namestr(&n->name), inet_ntoa(n->send_ip)));
+
+ if (!name_equal(&n->name, ans_name))
+ {
+ /* someone gave us the wrong name as a reply. oops. */
+ DEBUG(4,("unexpected name received: %s\n", namestr(ans_name)));
+ return;
+ }
+
+ if (nmb->header.rcode == 0 && nmb->answers->rdata)
+ {
+ int nb_flags = nmb->answers->rdata[0];
+ struct in_addr found_ip;
+
+ putip((char*)&found_ip,&nmb->answers->rdata[2]);
+
+ if (!ip_equal(n->send_ip, found_ip))
+ {
+ /* someone gave us the wrong ip as a reply. oops. */
+ DEBUG(4,("expected ip: %s\n", inet_ntoa(n->send_ip)));
+ DEBUG(4,("unexpected ip: %s\n", inet_ntoa(found_ip)));
+ return;
+ }
+
+ DEBUG(4, (" OK: %s\n", inet_ntoa(found_ip)));
+
+ if (n->state == NAME_QUERY_SYNC)
+ {
+ struct work_record *work = NULL;
+ if ((work = find_workgroupstruct(d, ans_name->name, False)))
+ {
+ /* the server is there: sync quick before it (possibly) dies! */
+ sync_browse_lists(d, work, ans_name->name, ans_name->name_type,
+ found_ip);
+ }
+ }
+ else
+ {
+ /* update our netbios name list (re-register it if necessary) */
+ add_netbios_entry(d, ans_name->name, ans_name->name_type,
+ nb_flags,GET_TTL(0),REGISTER,
+ found_ip,False,!bcast);
+ }
+ }
+ else
+ {
+ DEBUG(4, (" NEGATIVE RESPONSE!\n"));
+
+ if (n->state == NAME_QUERY_CONFIRM)
+ {
+ /* XXXX remove_netbios_entry()? */
+ /* lots of things we ought to do, here. if we get here,
+ then we're in a mess: our name database doesn't match
+ reality. sort it out
+ */
+ remove_netbios_name(d,n->name.name, n->name.name_type,
+ REGISTER,n->send_ip);
+ }
+ }
+}
+
+
+/****************************************************************************
+ report the response record type
+ ****************************************************************************/
+static void debug_rr_type(int rr_type)
+{
+ switch (rr_type)
+ {
+ case NMB_STATUS: DEBUG(3,("Name status ")); break;
+ case NMB_QUERY : DEBUG(3,("Name query ")); break;
+ case NMB_REG : DEBUG(3,("Name registration ")); break;
+ case NMB_REL : DEBUG(3,("Name release ")); break;
+ default : DEBUG(1,("wrong response packet type received")); break;
+ }
+}
+
+/****************************************************************************
+ report the response record nmbd state
+ ****************************************************************************/
+void debug_state_type(int state)
+{
+ /* report the state type to help debugging */
+ switch (state)
+ {
+ case NAME_QUERY_PDC_SRV_CHK : DEBUG(4,("MASTER_SVR_CHECK\n")); break;
+ case NAME_QUERY_SRV_CHK : DEBUG(4,("NAME_QUERY_SRV_CHK\n")); break;
+ case NAME_QUERY_FIND_MST : DEBUG(4,("NAME_QUERY_FIND_MST\n")); break;
+ case NAME_STATUS_PDC_SRV_CHK: DEBUG(4,("NAME_STAT_MST_CHK\n")); break;
+ case NAME_STATUS_SRV_CHK : DEBUG(4,("NAME_STATUS_SRV_CHK\n")); break;
+ case NAME_QUERY_MST_CHK : DEBUG(4,("NAME_QUERY_MST_CHK\n")); break;
+ case NAME_REGISTER : DEBUG(4,("NAME_REGISTER\n")); break;
+ case NAME_REGISTER_CHALLENGE: DEBUG(4,("NAME_REGISTER_CHALLENGE\n")); break;
+ case NAME_RELEASE : DEBUG(4,("NAME_RELEASE\n")); break;
+ case NAME_QUERY_CONFIRM : DEBUG(4,("NAME_QUERY_CONFIRM\n")); break;
+ case NAME_QUERY_SYNC : DEBUG(4,("NAME_QUERY_SYNC\n")); break;
+ default: break;
+ }
+}
+
+/****************************************************************************
+ report any problems with the fact that a response has been received.
+
+ (responses for certain types of operations are only expected from one host)
+ ****************************************************************************/
+static BOOL response_problem_check(struct response_record *n,
+ struct nmb_packet *nmb, char *qname)
+{
+ switch (nmb->answers->rr_type)
+ {
+ case NMB_REL:
+ {
+ if (n->num_msgs > 1)
+ {
+ DEBUG(1,("more than one release name response received!\n"));
+ return True;
+ }
+ break;
+ }
+
+ case NMB_REG:
+ {
+ if (n->num_msgs > 1)
+ {
+ DEBUG(1,("more than one register name response received!\n"));
+ return True;
+ }
+ break;
+ }
+
+ case NMB_QUERY:
+ {
+ if (n->num_msgs > 1)
+ {
+ if (nmb->header.rcode == 0 && nmb->answers->rdata)
+ {
+ int nb_flags = nmb->answers->rdata[0];
+
+ if ((!NAME_GROUP(nb_flags)))
+ {
+ /* oh dear. more than one person responded to a unique name.
+ there is either a network problem, a configuration problem
+ or a server is mis-behaving */
+
+ /* XXXX mark the name as in conflict, and then let the
+ person who just responded know that they must also mark it
+ as in conflict, and therefore must NOT use it.
+ see rfc1001.txt 15.1.3.5 */
+
+ /* this may cause problems for some early versions of nmbd */
+
+ switch (n->state)
+ {
+ case NAME_QUERY_FIND_MST:
+ {
+ /* query for ^1^2__MSBROWSE__^2^1 expect lots of responses */
+ return False;
+ }
+ case NAME_QUERY_PDC_SRV_CHK:
+ case NAME_QUERY_SRV_CHK:
+ case NAME_QUERY_MST_CHK:
+ {
+ if (!strequal(qname,n->name.name))
+ {
+ /* one subnet, one master browser per workgroup */
+ /* XXXX force an election? */
+
+ DEBUG(3,("more than one master browser replied!\n"));
+ return True;
+ }
+ break;
+ }
+ default: break;
+ }
+ DEBUG(3,("Unique Name conflict detected!\n"));
+ return True;
+ }
+ }
+ else
+ {
+ /* we have received a negative reply, having already received
+ at least one response (pos/neg). something's really wrong! */
+
+ DEBUG(3,("wierd name query problem detected!\n"));
+ return True;
+ }
+ }
+ }
+ }
+ return False;
+}
+
+/****************************************************************************
+ check that the response received is compatible with the response record
+ ****************************************************************************/
+static BOOL response_compatible(struct response_record *n,
+ struct nmb_packet *nmb)
+{
+ switch (n->state)
+ {
+ case NAME_RELEASE:
+ {
+ if (nmb->answers->rr_type != NMB_REL)
+ {
+ DEBUG(1,("Name release reply has wrong answer rr_type\n"));
+ return False;
+ }
+ break;
+ }
+
+ case NAME_REGISTER:
+ {
+ if (nmb->answers->rr_type != NMB_REG)
+ {
+ DEBUG(1,("Name register reply has wrong answer rr_type\n"));
+ return False;
+ }
+ break;
+ }
+
+ case NAME_REGISTER_CHALLENGE: /* this is a query: we then do a register */
+ case NAME_QUERY_CONFIRM:
+ case NAME_QUERY_SYNC:
+ case NAME_QUERY_PDC_SRV_CHK:
+ case NAME_QUERY_SRV_CHK:
+ case NAME_QUERY_FIND_MST:
+ case NAME_QUERY_MST_CHK:
+ {
+ if (nmb->answers->rr_type != NMB_QUERY)
+ {
+ DEBUG(1,("Name query reply has wrong answer rr_type\n"));
+ return False;
+ }
+ break;
+ }
+
+ case NAME_STATUS_PDC_SRV_CHK:
+ case NAME_STATUS_SRV_CHK:
+ {
+ if (nmb->answers->rr_type != NMB_STATUS)
+ {
+ DEBUG(1,("Name status reply has wrong answer rr_type\n"));
+ return False;
+ }
+ break;
+ }
+
+ default:
+ {
+ DEBUG(1,("unknown state type received in response_netbios_packet\n"));
+ return False;
+ }
+ }
+ return True;
+}
+
+
+/****************************************************************************
+ process the response packet received
+ ****************************************************************************/
+static void response_process(struct subnet_record *d, struct packet_struct *p,
+ struct response_record *n, struct nmb_packet *nmb,
+ BOOL bcast, struct nmb_name *ans_name)
+{
+ switch (n->state)
+ {
+ case NAME_RELEASE:
+ {
+ response_name_release(d, p);
+ break;
+ }
+
+ case NAME_REGISTER:
+ {
+ response_name_reg(d, p);
+ break;
+ }
+
+ case NAME_REGISTER_CHALLENGE:
+ {
+ response_name_query_register(nmb, ans_name, n, d);
+ break;
+ }
+
+ case NAME_QUERY_PDC_SRV_CHK:
+ case NAME_QUERY_SRV_CHK:
+ case NAME_QUERY_FIND_MST:
+ {
+ response_server_check(ans_name, n, d);
+ break;
+ }
+
+ case NAME_STATUS_PDC_SRV_CHK:
+ case NAME_STATUS_SRV_CHK:
+ {
+ response_name_status_check(p->ip, nmb, bcast, n, d);
+ break;
+ }
+
+ case NAME_QUERY_CONFIRM:
+ case NAME_QUERY_SYNC:
+ {
+ response_name_query_sync(nmb, ans_name, bcast, n, d);
+ break;
+ }
+ case NAME_QUERY_MST_CHK:
+ {
+ /* no action required here. it's when NO responses are received
+ that we need to do something. see expire_name_query_entries() */
+
+ DEBUG(4, ("Master browser exists for %s at %s (just checking!)\n",
+ namestr(&n->name), inet_ntoa(n->send_ip)));
+ break;
+ }
+
+ default:
+ {
+ DEBUG(1,("unknown state type received in response_netbios_packet\n"));
+ break;
+ }
+ }
+}
+
+
+/****************************************************************************
+ response from a netbios packet.
+ ****************************************************************************/
+void response_netbios_packet(struct packet_struct *p)
+{
+ struct nmb_packet *nmb = &p->packet.nmb;
+ struct nmb_name *question = &nmb->question.question_name;
+ struct nmb_name *ans_name = NULL;
+ char *qname = question->name;
+ BOOL bcast = nmb->header.nm_flags.bcast;
+ struct response_record *n;
+ struct subnet_record *d = NULL;
+
+ if (!(n = find_response_record(&d,nmb->header.name_trn_id))) {
+ DEBUG(2,("unknown netbios response (received late or from nmblookup?)\n"));
+ return;
+ }
+
+ if (!d)
+ {
+ DEBUG(2,("response packet: subnet %s not known\n", inet_ntoa(p->ip)));
+ return;
+ }
+
+ if (!same_net(d->bcast_ip, d->mask_ip, p->ip)) /* copes with WINS 'subnet' */
+ {
+ DEBUG(2,("response from %s. ", inet_ntoa(p->ip)));
+ DEBUG(2,("expected on subnet %s. hmm.\n", inet_ntoa(d->bcast_ip)));
+ return;
+ }
+
+ if (nmb->answers == NULL)
+ {
+ /* hm. the packet received was a response, but with no answer. wierd! */
+ DEBUG(2,("NMB packet response from %s (bcast=%s) - UNKNOWN\n",
+ inet_ntoa(p->ip), BOOLSTR(bcast)));
+ return;
+ }
+
+ ans_name = &nmb->answers->rr_name;
+ DEBUG(3,("response for %s from %s (bcast=%s)\n",
+ namestr(ans_name), inet_ntoa(p->ip), BOOLSTR(bcast)));
+
+ debug_rr_type(nmb->answers->rr_type);
+
+ n->num_msgs++; /* count number of responses received */
+ n->repeat_count = 0; /* don't resend: see expire_netbios_packets() */
+
+ debug_state_type(n->state);
+
+ /* problem checking: multiple responses etc */
+ if (response_problem_check(n, nmb, qname))
+ return;
+
+ /* now check whether the 'state' has received the correct type of response */
+ if (!response_compatible(n, nmb))
+ return;
+
+ /* now deal with the current state */
+ response_process(d, p, n, nmb, bcast, ans_name);
+}
+
+
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/nameservresp.doc samba-1.9.16alpha11/source/nameservresp.doc
--- samba-1.9.16alpha10/source/nameservresp.doc Thu Jan 1 10:00:00 1970
+++ samba-1.9.16alpha11/source/nameservresp.doc Thu Jul 11 04:48:29 1996
@@ -0,0 +1,164 @@
+this module deals with the receipt of response packets. the
+response packets are expected to be received, and there is a
+record of this kept (see also: modules nameresp and namedbresp)
+
+point of interest to design purists: every function in this
+module is static except response_netbios_packet().
+
+/*************************************************************************
+ response_netbios_packet()
+ *************************************************************************/
+
+this function receives netbios response packets. the samba server
+(or a rogue tcp/ip system, or nmblookup) will have sent out a packet
+requesting a response. a client (or a rogue tcp/ip system) responds
+to that request.
+
+this function checks the validity of the packet it receives.
+the expected response records are searched for the transaction id,
+to see if it's a response expected by the samba server. if it isn't
+it's reported as such, and ignored.
+
+if the response is found, then the subnet it was expected from will
+also have been found. the subnet it actually came in on can be
+checked against the subnet it was expected from and reported,
+otherwise this function just carries on.
+
+the number of responses received is increased, and the number of
+retries left to be sent is set to zero.
+
+after debug information is reported, and validation of the netbios
+packet (e.g only one response from one machine is expected for some
+functions) has occurred, the packet is processed. when the initial
+request was sent out, the expected response record was flagged with,
+for lack of a better word, a samba 'state' type. whenever a
+response is received, the appropriate function is called to carry on
+where the program control flow was interrupted while awaiting exactly
+such a response.
+
+please note that _not_ receiving a response is dealt with in another
+area of code - expire_netbios_response_entries().
+
+
+/*************************************************************************
+ response_name_query_sync()
+ *************************************************************************/
+
+this function receives responses to samba 'states' NAME_QUERY_SYNC and
+NAME_QUERY_CONFIRM.
+
+NAME_QUERY_SYNC: name query a server before synchronising browse lists.
+NAME_QUERY_CONFIRM: name query a server to check that it's alive.
+
+a NAME_QUERY_SYNC will be carried out in order to check that a server
+is alive before syncing browse lists. we don't want to delay the SMB
+NetServerEnum api just because the server has gone down: we have too
+much else to do.
+
+a NAME_QUERY_CONFIRM is just a name query to see whether the server is
+alive. these queries are sent out by samba's WINS server side, to verify
+its netbios name database of all machines that have registered with it.
+
+we don't normally expect a negative response from such a query, although
+we may do so if the query was sent to another WINS server. the registered
+entry should be removed if we receive a negative response.
+
+
+/*************************************************************************
+ response_name_status_check()
+ *************************************************************************/
+
+this function receives responses to samba 'states' NAME_STATUS_CHECK
+and NAME_STATUS_MASTER_CHECK
+
+NAME_STATUS_MASTER_CHECK: name status a primary domain controller,
+ confirm its domain and then initiate syncing
+ its browse list.
+
+NAME_STATUS_CHECK: same as NAME_STATUS_MASTER_CHECK except the name status
+ is issued to a master browser.
+
+if we don't know what workgroup a server is responsible for, but we
+know that there is a master browser at a certain ip, we can issue a
+name status check. from the response received, there will be
+a master browser netbios entry. this will allow us to synchronise
+browse lists with that machine and then add the information to the
+correct part of samba's workgroup - server database.
+
+
+/*************************************************************************
+ response_server_check()
+ *************************************************************************/
+
+this function receives responses to samba 'states' NAME_QUERY_MST_SRV_CHK,
+NAME_QUERY_SRV_CHK and NAME_QUERY_FIND_MST.
+
+NAME_QUERY_FIND_MST: issued as a broadcast when we wish to find out all
+ master browsers (i.e all servers that have registered
+ the NetBIOS name ^1^2__MSBROWSE__^2(0x1), and then
+ issue a NAME_STATUS_MASTER_CHECK on any servers that
+ respond, which will initiate a sync browse lists.
+
+NAME_QUERY_MST_SRV_CHK: same as a NAME_QUERY_FIND_MST except this is sent
+ to a primary domain controller.
+
+NAME_QUERY_SRV_CHK: same as a NAME_QUERY_MST_SRV_CHK except this is sent to
+ a master browser.
+
+the purpose of each of these states is to do a broadcast name query, or
+a name query directed at a WINS server, then to all hosts that respond,
+we issue a name status check, which will confirm for us the workgroup
+or domain name, and then initiate issuing a sync browse list call with
+that server.
+
+a NAME_QUERY_SRV_CHK is sent when samba receives a list of backup
+browsers. it checks to see if that server is alive (by doing a
+name query on a server) and then syncs browse lists with it.
+
+
+/*************************************************************************
+ response_name_reg()
+ *************************************************************************/
+
+this function is responsible for dealing with samba's registration
+attempts, by broadcast to a local subnet, or point-to-point with
+another WINS server.
+
+please note that it cannot cope with END-NODE CHALLENGE REGISTRATION
+RESPONSEs at present.
+
+when a response is received, samba determines if the response is a
+positive or a negative one. if it is a positive response, the name
+is added to samba's database.
+
+when a negative response is received, samba will remove the name
+from its database. if, however, the name is a browser type (0x1b is
+a primary domain controller type name; or 0x1d, which is a master
+browser type name) then it must also stop being a primary domain
+controller or master browser respectively, depending on what kind
+of name was rejected.
+
+(when no response is received, then expire_netbios_response_entries()
+is expected to deal with this. the only case that is dealt with here
+at present is when the registration was done by broadcast. if there
+is no challenge to the broadcast registration, it is implicitly
+assumed that claiming the name is acceptable).
+
+
+/*************************************************************************
+ response_name_release()
+ *************************************************************************/
+
+this function is responsible for removing samba's NetBIOS name when
+samba contacts another WINS server with which it had registered the
+name.
+
+only positive name releases are expected and dealt with. exactly what
+to do if a negative name release (i.e someone says 'oi! you have to
+keep that name!') is received is uncertain.
+
+(when no response is received, then expire_netbios_response_entries()
+is expected to deal with this. if there is no challenge to the release
+of the name, the name is then removed from that subnet's NetBIOS
+name database).
+
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/namework.c samba-1.9.16alpha11/source/namework.c
--- samba-1.9.16alpha10/source/namework.c Mon Jun 10 15:18:56 1996
+++ samba-1.9.16alpha11/source/namework.c Thu Jul 18 20:53:16 1996
@@ -2,7 +2,7 @@
Unix SMB/Netbios implementation.
Version 1.9.
NBT netbios routines and daemon - version 2
- Copyright (C) Andrew Tridgell 1994-1995
+ Copyright (C) Andrew Tridgell 1994-1996
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -45,9 +45,6 @@
extern int workgroup_count; /* total number of workgroups we know about */
-/* this is our browse cache database */
-extern struct browse_cache_record *browserlist;
-
/* this is our domain/workgroup/server database */
extern struct subnet_record *subnetlist;
@@ -67,13 +64,7 @@
extern time_t StartupTime;
-#define AM_MASTER(work) (work->ServerType & SV_TYPE_MASTER_BROWSER)
-#define AM_BACKUP(work) (work->ServerType & SV_TYPE_BACKUP_BROWSER)
-
-#define BROWSE_MAILSLOT "\\MAILSLOT\\BROWSE"
-
-#define GET_TTL(ttl) ((ttl)?MIN(ttl,lp_max_ttl()):lp_max_ttl())
-
+extern BOOL updatedlists;
/****************************************************************************
tell a server to become a backup browser
@@ -106,6 +97,11 @@
**************************************************************************/
void tell_become_backup(void)
{
+ /* XXXX note: this function is currently unsuitable for use, as it
+ does not properly check that a server is in a fit state to become
+ a backup browser before asking it to be one.
+ */
+
struct subnet_record *d;
for (d = subnetlist; d; d = d->next)
{
@@ -155,266 +151,6 @@
}
}
-/****************************************************************************
-find a server responsible for a workgroup, and sync browse lists
-**************************************************************************/
-static BOOL sync_browse_entry(struct browse_cache_record *b)
-{
- struct subnet_record *d;
- struct work_record *work;
- /*
- if (!strequal(serv_name, b->name))
- {
- DEBUG(0, ("browser's netbios name (%s) does not match %s (%s)",
- b->name, inet_ntoa(b->ip), serv_name));
- }
- */
- if (!(d = find_domain(b->ip))) return False;
- if (!(work = find_workgroupstruct(d, b->group, False))) return False;
-
- if (AM_MASTER(work)) {
- /* only try to sync browse lists if we are the master, otherwise
- the net could get a little bit too busy */
- sync_browse_lists(work,b->name,0x20,b->ip);
- }
- b->synced = True;
-
- return True;
-}
-
-
-/****************************************************************************
-search through browser list for an entry to sync with
-**************************************************************************/
-void do_browser_lists(void)
-{
- struct browse_cache_record *b;
- static time_t last = 0;
- time_t t = time(NULL);
-
- if (t-last < 20) return; /* don't do too many of these at once! */
-
- last = t;
-
- /* pick any entry in the list, preferably one whose time is up */
- for (b = browserlist; b && b->next; b = b->next)
- {
- if (b->sync_time < t && b->synced == False) break;
- }
-
- if (!b || b->synced || sync_browse_entry(b))
- {
- /* leave entries (even ones already sync'd) for up to a minute.
- this stops them getting re-sync'd too often */
- expire_browse_cache(t - 60);
- }
-}
-
-
-/****************************************************************************
-find a server responsible for a workgroup, and sync browse lists
-control ends up back here via response_name_query.
-**************************************************************************/
-void sync_server(enum cmd_type cmd, char *serv_name, char *work_name,
- int name_type,
- struct in_addr ip)
-{
- add_browser_entry(serv_name, name_type, work_name, 0, ip);
-
- if (cmd == MASTER_SERVER_CHECK)
- {
- /* announce ourselves as a master browser to serv_name */
- do_announce_request(myname, serv_name, ANN_MasterAnnouncement,
- 0x20, 0, ip);
- }
-}
-
-
-/****************************************************************************
-update workgroup database from a name registration
-**************************************************************************/
-void update_from_reg(char *name, int type, struct in_addr ip)
-{
- /* default server type: minimum guess at requirement XXXX */
-
- DEBUG(3,("update from registration: host %s ip %s type %0x\n",
- name, inet_ntoa(ip), type));
-
- /* workgroup types, but not a chat type */
- if (type >= 0x1b && type <= 0x1e)
- {
- struct work_record *work;
- struct subnet_record *d;
-
- if (!(d = find_domain(ip))) return;
- if (!(work = find_workgroupstruct(d, name, False))) return;
-
- /* request the server to announce if on our subnet */
- if (d->my_interface) announce_request(work, ip);
-
- /* domain master type or master browser type */
- if (type == 0x1b || type == 0x1d)
- {
- struct hostent *hp = gethostbyaddr((char*)&ip, sizeof(ip), AF_INET);
- if (hp) {
- /* gethostbyaddr name may not match netbios name but who cares */
- add_browser_entry(hp->h_name, type, work->work_group, 120, ip);
- }
- }
- }
-}
-
-
-/****************************************************************************
- add the default workgroup into my domain
- **************************************************************************/
-void add_my_domains(char *group)
-{
- int n,i;
- struct in_addr *ip;
-
- if (*group == '*') return;
-
- n = iface_count();
- for (i=0;i<n;i++) {
- ip = iface_n_ip(i);
- if (!ip) return;
- add_subnet_entry(*iface_bcast(*ip),*iface_nmask(*ip),lp_workgroup(),True);
- }
-}
-
-
-/****************************************************************************
- send a backup list response.
- **************************************************************************/
-static void send_backup_list(char *work_name, struct nmb_name *src_name,
- int info_count, int token, int info,
- int name_type, struct in_addr ip)
-{
- struct subnet_record *d;
- char outbuf[1024];
- char *p, *countptr, *nameptr;
- int count = 0;
- int i, j;
- char *theirname = src_name->name;
-
- DEBUG(3,("sending backup list of %s to %s: %s(%x) %s(%x)\n",
- work_name, inet_ntoa(ip),
- myname,0x20,theirname,0x0));
-
- if (name_type == 0x1d)
- {
- DEBUG(4,("master browsers: "));
- }
- else if (name_type == 0x1b)
- {
- DEBUG(4,("domain controllers: "));
- }
- else
- {
- DEBUG(0,("backup request for unknown type %0x\n", name_type));
- return;
- }
-
- bzero(outbuf,sizeof(outbuf));
- p = outbuf;
-
- CVAL(p,0) = 10; /* backup list response */
- p++;
-
- countptr = p; /* count pointer */
-
- SSVAL(p,1,token); /* sender's workgroup index representation */
- SSVAL(p,3,info); /* XXXX clueless: info, usually zero */
- p += 5;
-
- nameptr = p;
-
- for (d = subnetlist; d; d = d->next)
- {
- struct work_record *work;
-
- for (work = d->workgrouplist; work; work = work->next)
- {
- struct server_record *s;
-
- if (!strequal(work->work_group, work_name)) continue;
-
- for (s = work->serverlist; s; s = s->next)
- {
- BOOL found = False;
- char *n;
-
- if (s->serv.type & SV_TYPE_DOMAIN_ENUM) continue;
-
- for (n = nameptr; n < p; n = skip_string(n, 1))
- {
- if (strequal(n, s->serv.name)) found = True;
- }
-
- if (found) continue; /* exclude names already added */
-
- /* workgroup request: include all backup browsers in the list */
- /* domain request: include all domain members in the list */
-
- if ((name_type == 0x1d && (s->serv.type & MASTER_TYPE)) ||
- (name_type == 0x1b && (s->serv.type & DOMCTL_TYPE)))
- {
- DEBUG(4, ("%s ", s->serv.name));
-
- count++;
- strcpy(p,s->serv.name);
- strupper(p);
- p = skip_string(p,1);
- }
- }
- }
- }
-
- if (count == 0)
- {
- DEBUG(4, ("none\n"));
- return;
- }
- else
- {
- DEBUG(4, (" - count %d\n", count));
- }
-
- CVAL(countptr,0) = count; /* total number of backup browsers found */
-
- {
- int len = PTR_DIFF(p, outbuf);
-
- for (i = 0; i < len; i+= 16)
- {
- DEBUG(4, ("%3x char ", i));
-
- for (j = 0; j < 16; j++)
- {
- unsigned char x = outbuf[i+j];
- if (x < 32 || x > 127) x = '.';
-
- if (i+j >= len) break;
- DEBUG(4, ("%c", x));
- }
-
- DEBUG(4, (" hex ", i));
-
- for (j = 0; j < 16; j++)
- {
- if (i+j >= len) break;
- DEBUG(4, (" %02x", outbuf[i+j]));
- }
-
- DEBUG(4, ("\n"));
- }
-
- }
- send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
- myname,theirname,0x20,0,ip,*iface_ip(ip));
-}
-
/*******************************************************************
same context: scope. should check name_type as well, and makes sure
@@ -460,18 +196,22 @@
resources. We just have to pass it to smbd (via browser.dat) and let
the client choose using bit masks.
******************************************************************/
-static void process_announce(struct packet_struct *p,int command,char *buf)
+static void process_announce(struct packet_struct *p,uint16 command,char *buf)
{
struct dgram_packet *dgram = &p->packet.dgram;
struct in_addr ip = dgram->header.source_ip;
- struct subnet_record *d = find_domain(ip);
+ struct subnet_record *d = find_subnet(ip);
int update_count = CVAL(buf,0);
+
int ttl = IVAL(buf,1)/1000;
char *name = buf+5;
int osmajor=CVAL(buf,21);
int osminor=CVAL(buf,22);
uint32 servertype = IVAL(buf,23);
+ uint32 browse_type= CVAL(buf,27);
+ uint32 browse_sig = CVAL(buf,29);
char *comment = buf+31;
+
struct work_record *work;
char *work_name;
char *serv_name = dgram->source_name.name;
@@ -480,9 +220,9 @@
comment[43] = 0;
DEBUG(4,("Announce(%d) %s(%x)",command,name,name[15]));
- DEBUG(4,("%s count=%d ttl=%d OS=(%d,%d) type=%08x comment=%s\n",
+ DEBUG(4,("%s count=%d ttl=%d OS=(%d,%d) type=%08x sig=%4x %4x comment=%s\n",
namestr(&dgram->dest_name),update_count,ttl,osmajor,osminor,
- servertype,comment));
+ servertype,browse_type,browse_sig,comment));
name[15] = 0;
@@ -501,10 +241,20 @@
return;
}
- if (same_context(dgram)) return;
+ if (!strequal(dgram->dest_name.scope,scope )) return;
- if (command == ANN_DomainAnnouncement) {
+ if (command == ANN_DomainAnnouncement) {
+ /* XXXX if we are a master browser for the workgroup work_name,
+ then there is a local subnet configuration problem. only
+ we should be sending out such domain announcements, because
+ as the master browser, that is our job.
+
+ stop being a master browser, and force an election. this will
+ sort out the network problem. hopefully.
+ */
+
work_name = name;
+ add = True;
} else {
work_name = dgram->dest_name.name;
}
@@ -524,15 +274,24 @@
ttl = GET_TTL(ttl);
- /* add them to our browse list */
+ /* add them to our browse list, and update the browse.dat file */
add_server_entry(d,work,name,servertype,ttl,comment,True);
-
+ updatedlists = True;
+
#if 0
/* the tell become backup code is broken, no great harm is done by
disabling it */
tell_become_backup();
#endif
+ /* XXXX over-kill: i don't think we should really be doing this,
+ but it doesn't do much harm other than to add extra network
+ traffic. to be more precise, we should (possibly) only
+ sync browse lists with a host that sends an
+ ANN_LocalMasterAnnouncement or an ANN_DomainAnnouncement.
+ possibly.
+ */
+
/* get their browse list from them and add it to ours. */
add_browser_entry(serv_name,dgram->dest_name.name_type,
work->work_group,30,ip);
@@ -545,8 +304,8 @@
{
struct dgram_packet *dgram = &p->packet.dgram;
struct in_addr ip = dgram->header.source_ip;
- struct subnet_record *d = find_domain(ip);
- struct subnet_record *mydomain = find_domain(*iface_bcast(ip));
+ struct subnet_record *d = find_subnet(ip);
+ struct subnet_record *mydomain = find_subnet(*iface_bcast(ip));
char *name = buf;
struct work_record *work;
name[15] = 0;
@@ -575,18 +334,24 @@
we receive a list of servers, and we attempt to locate them all on
our local subnet, and sync browse lists with them on the workgroup
they are said to be in.
+
+ XXXX NOTE: this function is in overdrive. it should not really do
+ half of what it actually does (it should pick _one_ name from the
+ list received and sync with it at regular intervals, rather than
+ sync with them all only once!)
+
******************************************************************/
static void process_rcv_backup_list(struct packet_struct *p,char *buf)
{
struct dgram_packet *dgram = &p->packet.dgram;
struct in_addr ip = dgram->header.source_ip;
int count = CVAL(buf,0);
- int Index = IVAL(buf,1); /* caller's index representing workgroup */
+ uint32 info = IVAL(buf,1); /* XXXX caller's incremental info */
char *buf1;
- DEBUG(3,("Receive Backup ack for %s from %s total=%d index=%d\n",
+ DEBUG(3,("Receive Backup ack for %s from %s total=%d info=%d\n",
namestr(&dgram->dest_name), inet_ntoa(ip),
- count, Index));
+ count, info));
if (same_context(dgram)) return;
@@ -594,50 +359,170 @@
/* go through the list of servers attempting to sync browse lists */
for (buf1 = buf+5; *buf1 && count; buf1 = skip_string(buf1, 1), --count)
- {
- struct in_addr back_ip;
- struct subnet_record *d;
+ {
+ struct in_addr back_ip;
+ struct subnet_record *d;
- DEBUG(4,("Searching for backup browser %s at %s...\n",
+ DEBUG(4,("Searching for backup browser %s at %s...\n",
buf1, inet_ntoa(ip)));
- /* XXXX assume name is a DNS name NOT a netbios name. a more complete
- approach is to use reply_name_query functionality to find the name */
- back_ip = *interpret_addr2(buf1);
+ /* XXXX assume name is a DNS name NOT a netbios name. a more complete
+ approach is to use reply_name_query functionality to find the name */
+
+ back_ip = *interpret_addr2(buf1);
- if (zero_ip(back_ip))
+ if (zero_ip(back_ip))
{
DEBUG(4,("Failed to find backup browser server using DNS\n"));
continue;
}
DEBUG(4,("Found browser server at %s\n", inet_ntoa(back_ip)));
+ DEBUG(4,("END THIS LOOP: CODE NEEDS UPDATING\n"));
- if ((d = find_domain(back_ip)))
+ /* XXXX function needs work */
+ continue;
+
+ if ((d = find_subnet(back_ip)))
{
struct subnet_record *d1;
for (d1 = subnetlist; d1; d1 = d1->next)
- {
+ {
struct work_record *work;
for (work = d1->workgrouplist; work; work = work->next)
{
- if (work->token == Index)
- {
- queue_netbios_packet(ClientNMB,NMB_QUERY,SERVER_CHECK,
- work->work_group,0x1d,0,
- False,False,back_ip);
+ if (work->token == 0 /* token */)
+ {
+ queue_netbios_packet(d1,ClientNMB,NMB_QUERY,NAME_QUERY_SRV_CHK,
+ work->work_group,0x1d,0,0,
+ False,False,back_ip,back_ip);
return;
- }
+ }
}
- }
+ }
+ }
+ }
+}
+
+
+/****************************************************************************
+ send a backup list response.
+ **************************************************************************/
+static void send_backup_list(char *work_name, struct nmb_name *src_name,
+ int token, uint32 info,
+ int name_type, struct in_addr ip)
+{
+ char outbuf[1024];
+ char *p, *countptr, *nameptr;
+ int count = 0;
+ char *theirname = src_name->name;
+
+ DEBUG(3,("sending backup list of %s to %s: %s(%x) %s(%x)\n",
+ work_name, inet_ntoa(ip),
+ myname,0x0,theirname,0x0));
+
+ if (name_type == 0x1d)
+ {
+ DEBUG(4,("master browsers: "));
+ }
+ else if (name_type == 0x1b)
+ {
+ DEBUG(4,("domain controllers: "));
+ }
+ else
+ {
+ DEBUG(0,("backup request for unknown type %0x\n", name_type));
+ return;
+ }
+
+ bzero(outbuf,sizeof(outbuf));
+ p = outbuf;
+
+ CVAL(p,0) = ANN_GetBackupListResp; /* backup list response */
+
+ p++;
+ countptr = p;
+
+ SIVAL(p,1,info); /* the sender's unique info */
+
+ p += 5;
+
+ nameptr = p;
+
+#if 0
+
+ for (d = subnetlist; d; d = d->next)
+ {
+ struct work_record *work;
+
+ for (work = d->workgrouplist; work; work = work->next)
+ {
+ struct server_record *s;
+
+ if (!strequal(work->work_group, work_name)) continue;
+
+ for (s = work->serverlist; s; s = s->next)
+ {
+ BOOL found = False;
+ char *n;
+
+ if (s->serv.type & SV_TYPE_DOMAIN_ENUM) continue;
+
+ for (n = nameptr; n < p; n = skip_string(n, 1))
+ {
+ if (strequal(n, s->serv.name)) found = True;
+ }
+
+ if (found) continue; /* exclude names already added */
+
+ /* workgroup request: include all backup browsers in the list */
+ /* domain request: include all domain members in the list */
+
+ if ((name_type == 0x1d && (s->serv.type & MASTER_TYPE)) ||
+ (name_type == 0x1b && (s->serv.type & DOMCTL_TYPE)))
+ {
+ DEBUG(4, ("%s ", s->serv.name));
+
+ count++;
+ strcpy(p,s->serv.name);
+ strupper(p);
+ p = skip_string(p,1);
+ }
+ }
}
+ }
+
+#endif
+
+ count++;
+ strcpy(p,myname);
+ strupper(p);
+ p = skip_string(p,1);
+
+ if (count == 0)
+ {
+ DEBUG(4, ("none\n"));
+ }
+ else
+ {
+ DEBUG(4, (" - count %d\n", count));
}
+
+ CVAL(countptr, 0) = count;
+
+ {
+ int len = PTR_DIFF(p, outbuf);
+ debug_browse_data(outbuf, len);
+ }
+ send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
+ myname,theirname,0x0,0x0,ip,*iface_ip(ip));
}
+
/*******************************************************************
process a send backup list request
- A client send a backup list request to ask for a list of servers on
+ A client sends a backup list request to ask for a list of servers on
the net that maintain server lists for a domain. A server is then
chosen from this list to send NetServerEnum commands to to list
available servers.
@@ -650,18 +535,15 @@
{
struct dgram_packet *dgram = &p->packet.dgram;
struct in_addr ip = dgram->header.source_ip;
- struct subnet_record *d;
+ struct subnet_record *d;
struct work_record *work;
- int count = CVAL(buf,0);
- int token = SVAL(buf,1); /* sender's key index for the workgroup? */
- int info = SVAL(buf,3); /* XXXX don't know: some sort of info */
+ int token = CVAL(buf,0); /* sender's key index for the workgroup */
+ uint32 info = IVAL(buf,1); /* XXXX don't know: some sort of info */
int name_type = dgram->dest_name.name_type;
if (same_context(dgram)) return;
- if (count <= 0) return;
-
if (name_type != 0x1b && name_type != 0x1d) {
DEBUG(0,("backup request to wrong type %d from %s\n",
name_type,inet_ntoa(ip)));
@@ -674,11 +556,11 @@
{
if (strequal(work->work_group, dgram->dest_name.name))
{
- DEBUG(2,("sending backup list to %s %s count=%d\n",
- namestr(&dgram->dest_name),inet_ntoa(ip),count));
+ DEBUG(2,("sending backup list to %s %s id=%x\n",
+ namestr(&dgram->dest_name),inet_ntoa(ip),info));
send_backup_list(work->work_group,&dgram->source_name,
- count,token,info,name_type,ip);
+ token,info,name_type,ip);
return;
}
}
@@ -690,7 +572,7 @@
process a reset browser state
diagnostic packet:
- 0x1 - stop being a master browser
+ 0x1 - stop being a master browser and become a backup browser.
0x2 - discard browse lists, stop being a master browser, try again.
0x4 - stop being a master browser forever. no way. ain't gonna.
@@ -714,12 +596,16 @@
{
if (AM_MASTER(work))
{
- become_nonmaster(d,work);
+ become_nonmaster(d,work,SV_TYPE_DOMAIN_MASTER|SV_TYPE_MASTER_BROWSER);
}
}
}
}
+ /* XXXX documentation inconsistency: the above description does not
+ exactly tally with what is implemented for state & 0x2
+ */
+
/* totally delete all servers and start afresh */
if (state & 0x2)
{
@@ -727,9 +613,9 @@
for (d = subnetlist; d; d = d->next)
{
struct work_record *work;
- for (work=d->workgrouplist;work;work=remove_workgroup(d,work));
+ for (work=d->workgrouplist;work;work=remove_workgroup(d,work,True));
}
- add_my_domains(lp_workgroup());
+ add_my_subnets(lp_workgroup());
}
/* stop browsing altogether. i don't think this is a good idea! */
@@ -739,7 +625,6 @@
}
}
-
/*******************************************************************
process a announcement request
@@ -751,7 +636,7 @@
struct dgram_packet *dgram = &p->packet.dgram;
struct work_record *work;
struct in_addr ip = dgram->header.source_ip;
- struct subnet_record *d = find_domain(ip);
+ struct subnet_record *d = find_subnet(ip);
int token = CVAL(buf,0);
char *name = buf+1;
@@ -762,12 +647,23 @@
if (strequal(dgram->source_name.name,myname)) return;
+ /* XXXX BUG or FEATURE?: need to ensure that we are a member of
+ this workgroup before announcing, particularly as we only
+ respond on local interfaces anyway.
+
+ if (strequal(dgram->dest_name, lp_workgroup()) return; ???
+ */
+
if (!d) return;
if (!d->my_interface) return;
for (work = d->workgrouplist; work; work = work->next)
{
+ /* XXXX BUG: the destination name type should also be checked,
+ not just the name. e.g if the name is WORKGROUP(0x1d) then
+ we should only respond if we own that name */
+
if (strequal(dgram->dest_name.name,work->work_group))
{
work->needannounce = True;
@@ -777,89 +673,6 @@
/****************************************************************************
- process a domain logon packet
- **************************************************************************/
-void process_logon_packet(struct packet_struct *p,char *buf,int len)
-{
- struct dgram_packet *dgram = &p->packet.dgram;
- struct in_addr ip = dgram->header.source_ip;
- struct subnet_record *d = find_domain(ip);
- char *logname,*q;
- char *reply_name;
- BOOL add_slashes = False;
- pstring outbuf;
- int code,reply_code;
- struct work_record *work;
-
- if (!d) return;
-
- if (!(work = find_workgroupstruct(d,dgram->dest_name.name, False)))
- return;
-
- if (!lp_domain_logons()) {
- DEBUG(3,("No domain logons\n"));
- return;
- }
- if (!listening_name(work, &dgram->dest_name))
- {
- DEBUG(4,("Not listening to that domain\n"));
- return;
- }
-
- code = SVAL(buf,0);
- switch (code) {
- case 0:
- {
- char *machine = buf+2;
- char *user = skip_string(machine,1);
- logname = skip_string(user,1);
- reply_code = 6;
- reply_name = myname;
- add_slashes = True;
- DEBUG(3,("Domain login request from %s(%s) user=%s\n",
- machine,inet_ntoa(p->ip),user));
- }
- break;
- case 7:
- {
- char *machine = buf+2;
- logname = skip_string(machine,1);
- reply_code = 7;
- reply_name = lp_domain_controller();
- if (!*reply_name) {
- DEBUG(3,("No domain controller configured\n"));
- return;
- }
- DEBUG(3,("GETDC request from %s(%s)\n",
- machine,inet_ntoa(p->ip)));
- }
- break;
- default:
- DEBUG(3,("Unknown domain request %d\n",code));
- return;
- }
-
- bzero(outbuf,sizeof(outbuf));
- q = outbuf;
- SSVAL(q,0,reply_code);
- q += 2;
- if (add_slashes) {
- strcpy(q,"\\\\");
- q += 2;
- }
- StrnCpy(q,reply_name,16);
- strupper(q);
- q = skip_string(q,1);
- SSVAL(q,0,0xFFFF);
- q += 2;
-
- send_mailslot_reply(logname,ClientDGRAM,outbuf,PTR_DIFF(q,outbuf),
- myname,&dgram->source_name.name[0],0x20,0,p->ip,
- *iface_ip(p->ip));
-}
-
-
-/****************************************************************************
depending on what announce has been made, we are only going to
accept certain types of name announce. XXXX untested code
@@ -936,6 +749,7 @@
case ANN_DomainAnnouncement:
case ANN_LocalMasterAnnouncement:
{
+ debug_browse_data(buf, len);
process_announce(p,command,buf+1);
break;
}
@@ -954,15 +768,17 @@
case ANN_GetBackupListReq:
{
+ debug_browse_data(buf, len);
process_send_backup_list(p,buf+1);
break;
}
case ANN_GetBackupListResp:
- {
- process_rcv_backup_list(p, buf+1);
- break;
- }
+ {
+ debug_browse_data(buf, len);
+ process_rcv_backup_list(p, buf+1);
+ break;
+ }
case ANN_ResetBrowserState:
{
@@ -986,45 +802,4 @@
}
}
-
-/****************************************************************************
-process udp 138 datagrams
-****************************************************************************/
-void process_dgram(struct packet_struct *p)
-{
- char *buf;
- char *buf2;
- int len;
- struct dgram_packet *dgram = &p->packet.dgram;
-
- if (dgram->header.msg_type != 0x10 &&
- dgram->header.msg_type != 0x11 &&
- dgram->header.msg_type != 0x12) {
- /* don't process error packets etc yet */
- return;
- }
-
- buf = &dgram->data[0];
- buf -= 4; /* XXXX for the pseudo tcp length -
- someday I need to get rid of this */
-
- if (CVAL(buf,smb_com) != SMBtrans) return;
-
- len = SVAL(buf,smb_vwv11);
- buf2 = smb_base(buf) + SVAL(buf,smb_vwv12);
-
- DEBUG(4,("datagram from %s to %s for %s of type %d len=%d\n",
- namestr(&dgram->source_name),namestr(&dgram->dest_name),
- smb_buf(buf),CVAL(buf2,0),len));
-
-
- if (len <= 0) return;
-
- if (strequal(smb_buf(buf),"\\MAILSLOT\\BROWSE"))
- {
- process_browse_packet(p,buf2,len);
- } else if (strequal(smb_buf(buf),"\\MAILSLOT\\NET\\NETLOGON")) {
- process_logon_packet(p,buf2,len);
- }
-}
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/namework.doc samba-1.9.16alpha11/source/namework.doc
--- samba-1.9.16alpha10/source/namework.doc Thu Jan 1 10:00:00 1970
+++ samba-1.9.16alpha11/source/namework.doc Sun Jul 7 22:35:58 1996
@@ -0,0 +1,287 @@
+
+the module namework.c deals with NetBIOS datagram packets, primarily.
+it deals with nmbd's workgroup browser side and the domain log in
+side. none of the functionality here has specification documents available.
+empirical observation of packet traces has been the order of the day,
+along with some guess-work.
+
+beware!
+
+the receipt of datagram packets for workgroup browsing are dealt with here.
+some of the functions listed here will call others outside of this
+module, or will activate functionality dealt with by other modules
+(namedb, nameannounce, nameelect, namelogon, and namebrowse).
+
+
+/*************************************************************************
+ process_browse_packet()
+ *************************************************************************/
+
+this function is responsible for further identifying which type of
+browser datagram packet has been received, and dealing with it
+accordingly. if the packet is not dealt with, then an error is
+logged along with the type of packet that has been received.
+
+if listening_type() was in use, then it would be used here.
+
+the types of packets received and dealt with are:
+
+- ANN_HostAnnouncement
+- ANN_DomainAnnouncement
+- ANN_LocalMasterAnnouncement
+
+these are all identical in format and can all be processed by
+process_announce(). an announcement is received from a host
+(either a master browser telling us about itself, a server
+telling us about itself or a master browser telling us about
+a domain / workgroup)
+
+- ANN_AnnouncementRequest
+
+these are sent by master browsers or by servers. it is a
+request to announce ourselves as appropriate by sending
+either a ANN_HostAnnouncement datagram or both an
+ANN_DomainAnnouncement and an ANN_LocalMasterAnnouncement
+if we are a master browser (but not both).
+
+- ANN_Election
+
+this is an election datagram. if samba has been configured
+as a domain master then it will also send out election
+datagrams.
+
+- ANN_GetBackupListReq
+
+this is a request from another server for us to send a
+backup list of all servers that we know about. we respond
+by sending a datagram ANN_GetBackupListResp. the protocol
+here is a little dicey.
+
+- ANN_GetBackupListResp
+
+this is a response from another server that we have sent an
+ANN_GetBackupListReq to. the protocol is a little dicey.
+
+- ANN_BecomeBackup
+
+this is a message sent by a primary domain controller to a
+potential master browser, indicating that it should become
+a backup master browser for the workgroup it is a member
+of. samba does not respond at present to such datagrams,
+and it also sends out such datagrams for the wrong reasons
+(this code has now been disabled until this is fixed).
+
+- ANN_ResetBrowserState
+
+this datagram is sent by a primary domain controller (or
+anyone else, for that matter) for trouble-shooting purposes.
+it asks a browser to clear out its server lists, or to
+stop becoming a master browser altogether. NT/AS and
+samba do not implement this latter option.
+
+- ANN_MasterAnnouncement
+
+this datagram is sent by a master browser to a primary domain
+controller. it is a way to ensure that master browsers are
+kept in sync with a primary domain controller across a wide
+area network. on receipt of an ANN_MasterAnnouncement we
+should sync browse lists with the sender.
+
+(i never got the hang of this one when i was experimenting.
+i forget exactly what it's for, and i never fully worked
+out how to coax a server to send it. :-)
+
+
+/*************************************************************************
+ listening_type()
+ *************************************************************************/
+
+
+a datagram packet is sent from one NetBIOS name of a specific type
+to another NetBIOS name of a specific type. certain types of
+datagrams are only expected from certain types of NetBIOS names.
+
+this function is intended to catch errors in the type of datagrams
+received from different NetBIOS names. it is currently incomplete
+due to lack of information on the types of names and the datagrams
+they send.
+
+
+/*************************************************************************
+ process_announce_request()
+ *************************************************************************/
+
+this function is responsible for dealing with announcement requests.
+if the type of name that the request is sent to matches our current
+status, then we should respond. otherwise, the datagram should be
+ignored.
+
+samba only responds on its local subnets.
+
+at present, just the name is checked to see if the packet is for us.
+what should be done is that if we own the name (e.g WORGROUP(0x1d)
+or WORKGROUP(0x1b) then we should respond, otherwise, ignore the
+datagram.
+
+if the name is for us, and we are a member of that workgroup, then
+samba should respond.
+
+note that samba does not respond immediately. this is to ensure that
+if the master browser for the workgroup that samba is a member of
+sends out a broadcast request announcement, that that master browser
+is not swamped with replies. it is therefore up to samba to reply
+at some random interval. hence, a flag is set indicating the need
+to announce later.
+
+
+/*************************************************************************
+ process_reset_browser()
+ *************************************************************************/
+
+this function is responsible for dealing with reset state datagrams.
+there are three kinds of diagnostic reset requests:
+
+- stop being a master browser
+- discard browse lists, stop being a master browser, and run for re-election
+- stop being a master browser forever.
+
+samba and windows nt do not implement the latter option.
+
+there appears to be a discrepancy between this description and the
+code actually implemented.
+
+
+/*************************************************************************
+ process_send_backup_list()
+ *************************************************************************/
+
+this function is part of samba's primary domain controller functionality.
+
+it is responsible for giving master browsers a list of other browsers
+that maintain backup lists of servers for that master browser's workgroup.
+
+it is also responsible for giving master browsers a list of primary domain
+controllers for that master browser's domain.
+
+a correct way to think of this function is that it is a 'request to
+send out a backup list for the requested workgroup or domain'.
+
+i have some suspicions and intuitions about this function and how it
+is to actually be used. there is no documentation on this, so it is a
+matter of experimenting until it's right.
+
+
+/*************************************************************************
+ send_backup_list()
+ *************************************************************************/
+
+this function is responsible for compiling a list of either master
+browsers and backup master browsers or primary domain controllers or
+backup domain controllers. samba constructs this list from its
+workgroup / server database.
+
+the list is then sent to the host that requested it by sending an
+ANN_GetBackupListResp datagram to this host.
+
+
+/*************************************************************************
+ process_rcv_backup_list()
+ *************************************************************************/
+
+this function is implemented with a slightly over-kill algorithm.
+the correct functionality is to pick any three names at random from
+the list that is received from this datagram, and then at intervals
+contact _one_ of them for a list of browser, in order to update
+samba's browse list.
+
+samba contacts every single one of the backup browsers listed, through
+the use of a NAME_QUERY_SRV_CHK 'state'.
+
+
+/*************************************************************************
+ process_master_announce()
+ *************************************************************************/
+
+this function is responsible for synchronising browse lists with a
+master browser that contacts samba in its capacity as a primary
+domain controller.
+
+the function add_browser_entry() is used to add the server that
+contacts us to our list of browser to sync browse lists with at
+some point in the near future.
+
+
+/*************************************************************************
+ process_announce()
+ *************************************************************************/
+
+this function is responsible for dealing with the three types of
+announcement type datagrams that samba recognises. some appropriate
+type-checking is done on the name that the datagram is sent to.
+
+samba does not at present deal with LanManager announcements.
+
+these announcements are for updating the browse entry records.
+each browse entry has a time-to-live associated with it. each server
+must refresh its entry with all other servers by broadcasting
+Announcements. if it does not do so, then other servers will not
+know about that machine, and the records on each server of that
+other machine will die.
+
+if an ANN_DomainAnnouncement is received, then this will be from
+a master browser. only one machine on any given broadcast area (e.g
+a subnet) should be broadcasting such announcements. the information
+it contains tells other servers that there is a master browser for
+this workgroup. if another server thinks that it is also a master
+browser for the same workgroup, then it should stop being a master
+browser and force an election.
+
+if an ANN_LocalMasterAnnouncement is received, then a master browser
+is telling us that it exists. i am uncertain that anything else
+actually needs to be done with this, other than to shout 'hooray' and
+'thank you for informing me of this fact'.
+
+
+/*************************************************************************
+ listening_name()
+ *************************************************************************/
+
+this function is an over-simplified way of identifying whether we
+should be responding to a datagram that has been received.
+
+
+/*************************************************************************
+ same_context()
+ *************************************************************************/
+
+this function helps us to identify whether we should be responding to
+a datagram that has been received.
+
+
+/*************************************************************************
+ tell_become_backup()
+ *************************************************************************/
+
+this function is part of samba's primary domain controller capabilities.
+it is responsible for finding appropriate servers to tell to become a
+backup master browser for the domain that samba controls.
+
+other servers that contact samba asking for a list of backup browsers
+will then be given that server's name, and that server can expect to
+receive NetServerEnum requests for lists of servers and workgroups.
+
+this function must be updated before it is in a fit state to be used.
+it must properly check whether a server is prepared to become a backup
+browser before actually asking it to be one.
+
+
+/*************************************************************************
+ reset_server()
+ *************************************************************************/
+
+this function is responsible for issuing an ANN_ResetBrowserState to
+the specified server, asking it to reset its browser information.
+
+see process_reset_browser() for details on this function.
+
+
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/nmbd.c samba-1.9.16alpha11/source/nmbd.c
--- samba-1.9.16alpha10/source/nmbd.c Mon Jun 10 15:18:56 1996
+++ samba-1.9.16alpha11/source/nmbd.c Thu Jul 18 20:53:16 1996
@@ -55,21 +55,24 @@
/****************************************************************************
-catch a sigterm
-****************************************************************************/
+ catch a sigterm
+ ****************************************************************************/
static int sig_term()
{
BlockSignals(True);
DEBUG(0,("Got SIGTERM: going down...\n"));
+ /* write out wins.dat file if samba is a WINS server */
dump_names();
- reload_services(True);
/* remove all samba names, with wins server if necessary. */
remove_my_names();
+ /* announce all server entries as 0 time-to-live, 0 type */
/* XXXX don't care if we never receive a response back... yet */
+ remove_my_servers();
+
/* XXXX other things: if we are a master browser, force an election? */
exit(0);
@@ -204,6 +207,7 @@
}
load_interfaces();
+ add_subnet_interfaces();
return(ret);
}
@@ -286,9 +290,13 @@
ipmask = *iface_nmask(ipaddr);
if (group) {
- add_subnet_entry(ipaddr, ipmask, name, True);
+ add_subnet_entry(ipaddr, ipmask, name, True, True);
} else {
- add_netbios_entry(name,0x20,NB_ACTIVE,0,source,ipaddr,True);
+ struct subnet_record *d = find_subnet(ipaddr);
+ if (d)
+ {
+ add_netbios_entry(d,name,0x20,NB_ACTIVE,0,source,ipaddr,True,True);
+ }
}
}
}
@@ -315,17 +323,20 @@
announce_host();
-#if 0
- /* what was this stuff supposed to do? It sent
+#if 1
+ /* XXXX what was this stuff supposed to do? It sent
ANN_GetBackupListReq packets which I think should only be
sent when trying to find out who to browse with */
+
announce_backup();
#endif
announce_master();
+ query_refresh_names();
+
expire_names_and_servers();
- expire_netbios_response_entries(t-10);
+ expire_netbios_response_entries();
refresh_my_names(t);
write_browse_list();
@@ -446,7 +457,7 @@
fault_setup(fault_continue);
- signal(SIGHUP,SIGNAL_CAST sig_hup);
+ signal(SIGHUP ,SIGNAL_CAST sig_hup);
signal(SIGTERM,SIGNAL_CAST sig_term);
while ((opt = getopt(argc, argv, "s:T:I:C:bAi:B:N:Rn:l:d:Dp:hSH:G:")) != EOF)
@@ -514,7 +525,7 @@
return(-1);
if (*group)
- add_my_domains(group);
+ add_my_subnets(group);
if (!is_daemon && !is_a_socket(0)) {
DEBUG(0,("standard input is not a socket, assuming -D option\n"));
@@ -535,16 +546,22 @@
DEBUG(3,("Loaded hosts file\n"));
}
+
+
if (!*ServerComment)
strcpy(ServerComment,"Samba %v");
string_sub(ServerComment,"%v",VERSION);
string_sub(ServerComment,"%h",myhostname);
add_my_names();
- add_my_domains(lp_workgroup());
+ add_my_subnets(lp_workgroup());
DEBUG(3,("Checked names\n"));
+ load_netbios_names();
+
+ DEBUG(3,("Loaded names\n"));
+
write_browse_list();
DEBUG(3,("Dumped names\n"));
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/nmblookup.c samba-1.9.16alpha11/source/nmblookup.c
--- samba-1.9.16alpha10/source/nmblookup.c Sat Jun 8 15:37:54 1996
+++ samba-1.9.16alpha11/source/nmblookup.c Thu Jul 18 20:53:16 1996
@@ -49,7 +49,7 @@
return False;
}
- ServerFD = open_socket_in(SOCK_DGRAM, 0,3);
+ ServerFD = open_socket_in(SOCK_DGRAM, NMB_PORT,3);
if (ServerFD == -1)
return(False);
@@ -93,7 +93,7 @@
int main(int argc,char *argv[])
{
int opt;
- unsigned int lookup_type = 0;
+ unsigned int lookup_type = 0x0;
pstring lookup;
extern int optind;
extern char *optarg;
@@ -164,7 +164,7 @@
strcpy(lookup,"\01\02__MSBROWSE__\02");
lookup_type = 1;
} else {
- lookup_type = 0x1d;
+ lookup_type = 0x1b;
}
}
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/nmbsync.c samba-1.9.16alpha11/source/nmbsync.c
--- samba-1.9.16alpha10/source/nmbsync.c Mon Jun 10 15:18:57 1996
+++ samba-1.9.16alpha11/source/nmbsync.c Mon Jul 15 17:55:05 1996
@@ -102,6 +102,7 @@
uint32 stype = IVAL(p,18);
int comment_offset = IVAL(p,22) & 0xFFFF;
char *cmnt = comment_offset?(rdata+comment_offset-converter):"";
+
struct work_record *w = work;
DEBUG(4, ("\t%-16.16s %08x %s\n", sname, stype, cmnt));
@@ -109,17 +110,17 @@
if (stype & SV_TYPE_DOMAIN_ENUM)
{
/* creates workgroup on remote subnet */
- if ((w = find_workgroupstruct(d,sname, True)))
+ if ((w = find_workgroupstruct(d,sname,True)))
{
if (d->my_interface)
{
announce_request(w, d->bcast_ip);
}
}
- }
+ }
- if (w)
- add_server_entry(d,w,sname,stype,lp_max_ttl(),cmnt,False);
+ if (w)
+ add_server_entry(d,w,sname,stype,lp_max_ttl(),cmnt,False);
}
}
}
@@ -137,10 +138,11 @@
log in on the remote server's SMB port to their IPC$ service,
do a NetServerEnum and update our server and workgroup databases.
******************************************************************/
-void sync_browse_lists(struct work_record *work, char *name, int nm_type,
- struct in_addr ip)
+void sync_browse_lists(struct subnet_record *d, struct work_record *work,
+ char *name, int nm_type, struct in_addr ip)
{
- struct subnet_record *d;
+ if (!d || !work || !AM_MASTER(work)) return;
+
pid = getpid();
uid = getuid();
gid = getgid();
@@ -158,8 +160,6 @@
if (zero_ip(dest_ip)) return;
have_ip = True;
-
- if (!(d = find_domain(ip))) return;
connect_as_ipc = True;
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/printing.c samba-1.9.16alpha11/source/printing.c
--- samba-1.9.16alpha10/source/printing.c Mon Jun 10 15:18:59 1996
+++ samba-1.9.16alpha11/source/printing.c Sun Jun 30 15:17:26 1996
@@ -600,10 +600,19 @@
/****************************************************************************
parse a lpq line for the plp printing system
Bertrand Wallrich <Bertrand.Wallrich@loria.fr>
+
+redone by tridge. Here is a sample queue:
+
+Local Printer 'lp2' (fjall):
+ Printing (started at Jun 15 13:33:58, attempt 1).
+ Rank Owner Pr Opt Job Host Files Size Date
+ active tridge X - 6 fjall /etc/hosts 739 Jun 15 13:33
+ 3rd tridge X - 7 fjall /etc/hosts 739 Jun 15 13:33
+
****************************************************************************/
static BOOL parse_lpq_plp(char *line,print_queue_struct *buf,BOOL first)
{
- string tok[5];
+ string tok[11];
int count=0;
/* handle the case of "(standard input)" as a filename */
@@ -611,60 +620,49 @@
string_sub(line,"(","\"");
string_sub(line,")","\"");
- for (count=0; count<8 && next_token(&line,tok[count],NULL); count++) ;
+ for (count=0; count<11 && next_token(&line,tok[count],NULL); count++) ;
+
+ /* we must get 11 tokens */
+ if (count < 11)
+ return(False);
- /* we must get 5 tokens */
- if (count < 8)
+ /* the first must be "active" or begin with an integer */
+ if (strcmp(tok[0],"active") && !isdigit(tok[0][0]))
return(False);
- /* the 4rd must be integer */
- if (!isdigit(*tok[3])) return(False);
+ /* the 5th and 8th must be integer */
+ if (!isdigit(*tok[4]) || !isdigit(*tok[7]))
+ return(False);
/* if the fname contains a space then use STDIN */
- if (strchr(tok[3],' '))
- strcpy(tok[3],"STDIN");
+ if (strchr(tok[6],' '))
+ strcpy(tok[6],"STDIN");
/* only take the last part of the filename */
{
string tmp;
- char *p = strrchr(tok[5],'/');
+ char *p = strrchr(tok[6],'/');
if (p)
{
strcpy(tmp,p+1);
- strcpy(tok[5],tmp);
+ strcpy(tok[6],tmp);
}
}
- buf->job = atoi(tok[3]);
+ buf->job = atoi(tok[4]);
- /* calcul de la taille du fichier */
- if (!isdigit(*tok[7])) { buf->size = atoi(tok[7]) * 1.0 ; }
- else {
- string tmp;
- strcpy(tmp,tok[7]);
- if (strchr(tok[7],'K')) {
- strncpy(tok[7],tmp,strlen(tmp)-1);
- buf->size = atoi(tok[7]);
- buf->size = buf->size * 1024;
- }
- if (strchr(tok[7],'M')) {
- strncpy(tok[7],tmp,strlen(tmp)-1);
- buf->size = atoi(tok[7]);
- buf->size = buf->size * 1024.0 * 1000.0;
- }
- if (strchr(tok[7],'G')) {
- strncpy(tok[7],tmp,strlen(tmp)-1);
- buf->size = atoi(tok[7]);
- buf->size = buf->size * 1024.0 * 1000000.0;
- }
+ buf->size = atoi(tok[7]);
+ if (strchr(tok[7],'K'))
+ buf->size *= 1024;
+ if (strchr(tok[7],'M'))
+ buf->size *= 1024*1024;
- }
buf->status = strequal(tok[0],"active")?LPQ_PRINTING:LPQ_QUEUED;
buf->priority = 0;
buf->time = time(NULL);
StrnCpy(buf->user,tok[1],sizeof(buf->user)-1);
- StrnCpy(buf->file,tok[5],sizeof(buf->file)-1);
+ StrnCpy(buf->file,tok[6],sizeof(buf->file)-1);
return(True);
}
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/proto.h samba-1.9.16alpha11/source/proto.h
--- samba-1.9.16alpha10/source/proto.h Mon Jun 10 15:18:59 1996
+++ samba-1.9.16alpha11/source/proto.h Thu Jul 18 20:53:16 1996
@@ -1,20 +1,39 @@
/* This file is automatically generated with "make proto". DO NOT EDIT */
+
+
+/*The following definitions come from access.c */
+
BOOL check_access(int snum);
BOOL allow_access(char *deny_list,char *allow_list,struct from_host *client);
BOOL fromhost(int sock,struct from_host *f);
+
+/*The following definitions come from charcnv.c */
+
char *unix2dos_format(char *str,BOOL overwrite);
char *dos2unix_format(char *str, BOOL overwrite);
int interpret_character_set(char *str, int def);
+
+/*The following definitions come from charset.c */
+
void charset_initialise(void);
void add_char_string(char *s);
+
+/*The following definitions come from chgpasswd.c */
+
BOOL chat_with_program(char *passwordprogram,char *name,char *chatsequence);
BOOL chgpasswd(char *name,char *oldpass,char *newpass);
BOOL chgpasswd(char *name,char *oldpass,char *newpass);
+
+/*The following definitions come from client.c */
+
void setup_pkt(char *outbuf);
void do_dir(char *inbuf,char *outbuf,char *Mask,int attribute,void (*fn)(),BOOL recurse_dir);
void cmd_help(void);
BOOL reopen_connection(char *inbuf,char *outbuf);
char *smb_errstr(char *inbuf);
+
+/*The following definitions come from clientutil.c */
+
void cli_setup_pkt(char *outbuf);
BOOL cli_receive_trans_response(char *inbuf,int trans,int *data_len,
int *param_len, char **data,char **param);
@@ -29,6 +48,9 @@
BOOL cli_open_sockets(int port);
BOOL cli_reopen_connection(char *inbuf,char *outbuf);
char *smb_errstr(char *inbuf);
+
+/*The following definitions come from clitar.c */
+
int strslashcmp(const char *s1, const char *s2);
void cmd_block(void);
void cmd_tarmode(void);
@@ -37,6 +59,9 @@
int process_tar(char *inbuf, char *outbuf);
int clipfind(char **aret, int ret, char *tok);
int tar_parseargs(int argc, char *argv[], char *Optarg, int Optind);
+
+/*The following definitions come from dir.c */
+
void init_dptrs(void);
char *dptr_path(int key);
char *dptr_wcard(int key);
@@ -62,8 +87,17 @@
void DirCacheAdd(char *path,char *name,char *dname,int snum);
char *DirCacheCheck(char *path,char *name,int snum);
void DirCacheFlush(int snum);
+
+/*The following definitions come from fault.c */
+
void fault_setup(void (*fn)());
+
+/*The following definitions come from getsmbpass.c */
+
char *getsmbpass(char *prompt) ;
+
+/*The following definitions come from interface.c */
+
void load_interfaces(void);
void iface_set_default(char *ip,char *bcast,char *nmask);
BOOL ismyip(struct in_addr ip);
@@ -73,8 +107,17 @@
struct in_addr *iface_bcast(struct in_addr ip);
struct in_addr *iface_nmask(struct in_addr ip);
struct in_addr *iface_ip(struct in_addr ip);
+
+/*The following definitions come from ipc.c */
+
int reply_trans(char *inbuf,char *outbuf);
+
+/*The following definitions come from kanji.c */
+
int interpret_coding_system(char *str, int def);
+
+/*The following definitions come from loadparm.c */
+
char *lp_string(char *s);
char *lp_logfile(void);
char *lp_smbrun(void);
@@ -99,6 +142,7 @@
char *lp_logon_script(void);
char *lp_wins_server(void);
char *lp_interfaces(void);
+char *lp_remote_interfaces(void);
BOOL lp_wins_support(void);
BOOL lp_wins_proxy(void);
BOOL lp_domain_master(void);
@@ -206,6 +250,9 @@
int lp_servicenumber(char *pszServiceName);
char *my_workgroup(void);
char *volume_label(int snum);
+
+/*The following definitions come from locking.c */
+
BOOL fcntl_lock(int fd,int op,uint32 offset,uint32 count,int type);
int file_lock(char *name,int timeout);
void file_unlock(int fd);
@@ -218,6 +265,9 @@
void del_share_mode(int fnum);
BOOL set_share_mode(int fnum,int mode);
void clean_share_files(void);
+
+/*The following definitions come from mangle.c */
+
int str_checksum(char *s);
BOOL is_8_3(char *fname);
void create_mangled_stack(int size);
@@ -225,109 +275,217 @@
BOOL is_mangled(char *s);
void mangle_name_83(char *s);
BOOL name_map_mangle(char *OutName,BOOL need83,int snum);
+
+/*The following definitions come from md4.c */
+
+
+/*The following definitions come from message.c */
+
int reply_sends(char *inbuf,char *outbuf);
int reply_sendstrt(char *inbuf,char *outbuf);
int reply_sendtxt(char *inbuf,char *outbuf);
int reply_sendend(char *inbuf,char *outbuf);
+
+/*The following definitions come from nameannounce.c */
+
void announce_request(struct work_record *work, struct in_addr ip);
void do_announce_request(char *info, char *to_name, int announce_type,
int from,
int to, struct in_addr dest_ip);
+void sync_server(enum state_type state, char *serv_name, char *work_name,
+ int name_type,
+ struct in_addr ip);
void announce_backup(void);
+void remove_my_servers(void);
+void announce_server(struct subnet_record *d, struct work_record *work,
+ char *name, char *comment, time_t ttl, int server_type);
void announce_host(void);
void announce_master(void);
-struct work_record *remove_workgroup(struct subnet_record *d,
- struct work_record *work);
+
+/*The following definitions come from namebrowse.c */
+
void expire_browse_cache(time_t t);
-struct work_record *find_workgroupstruct(struct subnet_record *d,
- fstring name, BOOL add);
-struct subnet_record *find_domain(struct in_addr ip);
-void dump_workgroups(void);
-struct subnet_record *add_subnet_entry(struct in_addr source_ip,
- struct in_addr source_mask,
- char *name, BOOL add);
struct browse_cache_record *add_browser_entry(char *name, int type, char *wg,
time_t ttl, struct in_addr ip);
+void do_browser_lists(void);
+
+/*The following definitions come from namedbname.c */
+
+BOOL name_equal(struct nmb_name *n1,struct nmb_name *n2);
+BOOL ms_browser_name(char *name, int type);
+void remove_name(struct subnet_record *d, struct name_record *n);
+struct name_record *find_name(struct name_record *n,
+ struct nmb_name *name,
+ int search);
+struct name_record *find_name_search(struct subnet_record **d,
+ struct nmb_name *name,
+ int search, struct in_addr ip);
+void dump_names(void);
+void load_netbios_names(void);
+void remove_netbios_name(struct subnet_record *d,
+ char *name,int type, enum name_source source,
+ struct in_addr ip);
+struct name_record *add_netbios_entry(struct subnet_record *d,
+ char *name, int type, int nb_flags,
+ int ttl, enum name_source source, struct in_addr ip,
+ BOOL new_only,BOOL wins);
+void expire_names(time_t t);
+struct name_record *search_for_name(struct subnet_record **d,
+ struct nmb_name *question,
+ struct in_addr ip, int Time, int search);
+
+/*The following definitions come from namedbresp.c */
+
+void add_response_record(struct subnet_record *d,
+ struct response_record *n);
+void remove_response_record(struct subnet_record *d,
+ struct response_record *n);
+struct response_record *make_response_queue_record(enum state_type state,
+ int id,uint16 fd,
+ int quest_type, char *name,int type, int nb_flags, time_t ttl,
+ BOOL bcast,BOOL recurse,
+ struct in_addr send_ip, struct in_addr reply_to_ip);
+struct response_record *find_response_record(struct subnet_record **d,
+ uint16 id);
+
+/*The following definitions come from namedbserver.c */
+
+void remove_old_servers(struct work_record *work, time_t t,
+ BOOL remove_all);
+struct server_record *find_server(struct work_record *work, char *name);
struct server_record *add_server_entry(struct subnet_record *d,
struct work_record *work,
char *name,int servertype,
int ttl,char *comment,
BOOL replace);
-void write_browse_list(void);
void expire_servers(time_t t);
+
+/*The following definitions come from namedbsubnet.c */
+
+struct subnet_record *find_subnet(struct in_addr bcast_ip);
+struct subnet_record *find_req_subnet(struct in_addr ip, BOOL bcast);
+void add_subnet_interfaces(void);
+void add_my_subnets(char *group);
+struct subnet_record *add_subnet_entry(struct in_addr bcast_ip,
+ struct in_addr mask_ip,
+ char *name, BOOL add, BOOL lmhosts);
+void write_browse_list(void);
+
+/*The following definitions come from namedbwork.c */
+
+struct work_record *remove_workgroup(struct subnet_record *d,
+ struct work_record *work,
+ BOOL remove_all_servers);
+struct work_record *find_workgroupstruct(struct subnet_record *d,
+ fstring name, BOOL add);
+void dump_workgroups(void);
+
+/*The following definitions come from nameelect.c */
+
void check_master_browser(void);
void browser_gone(char *work_name, struct in_addr ip);
void send_election(struct subnet_record *d, char *group,uint32 criterion,
int timeup,char *name);
-void become_nonmaster(struct subnet_record *d, struct work_record *work);
+void name_unregister_work(struct subnet_record *d, char *name, int name_type);
+void name_register_work(struct subnet_record *d, char *name, int name_type,
+ int nb_flags, time_t ttl, struct in_addr ip, BOOL bcast);
+void become_master(struct subnet_record *d, struct work_record *work);
+void become_nonmaster(struct subnet_record *d, struct work_record *work,
+ int remove_type);
void run_elections(void);
void process_election(struct packet_struct *p,char *buf);
BOOL check_elections(void);
-BOOL name_status(int fd,char *name,int name_type,BOOL recurse,
- struct in_addr to_ip,char *master,char *rname,
- void (*fn)());
-BOOL name_query(int fd,char *name,int name_type,
- BOOL bcast,BOOL recurse,
- struct in_addr to_ip, struct in_addr *ip,void (*fn)());
-void expire_netbios_response_entries(time_t t);
-void reply_netbios_packet(struct packet_struct *p1,int trn_id,int rcode,
- int opcode,BOOL recurse,struct nmb_name *rr_name,
- int rr_type,int rr_class,int ttl,char *data,int len);
-uint16 initiate_netbios_packet(int fd,int quest_type,char *name,int name_type,
- int nb_flags,BOOL bcast,BOOL recurse,
- struct in_addr to_ip);
-void queue_netbios_pkt_wins(int fd,int quest_type,enum cmd_type cmd,
- char *name,int name_type,int nb_flags,
- BOOL bcast,BOOL recurse,struct in_addr to_ip);
-void queue_netbios_packet(int fd,int quest_type,enum cmd_type cmd,char *name,
- int name_type,int nb_flags,BOOL bcast,BOOL recurse,
- struct in_addr to_ip);
-struct name_response_record *find_name_query(uint16 id);
+
+/*The following definitions come from namelogon.c */
+
+void process_logon_packet(struct packet_struct *p,char *buf,int len);
+
+/*The following definitions come from namepacket.c */
+
+void debug_browse_data(char *outbuf, int len);
+void initiate_netbios_packet(uint16 *id,
+ int fd,int quest_type,char *name,int name_type,
+ int nb_flags,BOOL bcast,BOOL recurse,
+ struct in_addr to_ip);
+void reply_netbios_packet(struct packet_struct *p1,int trn_id,
+ int rcode, int rcv_code, int opcode, BOOL recurse,
+ struct nmb_name *rr_name,int rr_type,int rr_class,int ttl,
+ char *data,int len);
void queue_packet(struct packet_struct *packet);
void run_packet_queue();
void listen_for_packets(BOOL run_election);
-BOOL interpret_node_status(char *p, struct nmb_name *name,int t,
- char *serv_name, struct in_addr ip);
BOOL send_mailslot_reply(char *mailslot,int fd,char *buf,int len,char *srcname,
char *dstname,int src_type,int dest_type,
struct in_addr dest_ip,struct in_addr src_ip);
-void remove_name(struct name_record *n);
-void dump_names(void);
-void remove_netbios_name(char *name,int type, enum name_source source,
- struct in_addr ip);
-struct name_record *add_netbios_entry(char *name, int type, int nb_flags,
- int ttl,
- enum name_source source,
- struct in_addr ip,
- BOOL new_only);
-void remove_name_entry(char *name,int type);
-void add_name_entry(char *name,int type,int nb_flags);
+
+/*The following definitions come from namequery.c */
+
+BOOL name_status(int fd,char *name,int name_type,BOOL recurse,
+ struct in_addr to_ip,char *master,char *rname,
+ void (*fn)());
+BOOL name_query(int fd,char *name,int name_type,
+ BOOL bcast,BOOL recurse,
+ struct in_addr to_ip, struct in_addr *ip,void (*fn)());
+
+/*The following definitions come from nameresp.c */
+
+void expire_netbios_response_entries();
+struct response_record *queue_netbios_pkt_wins(struct subnet_record *d,
+ int fd,int quest_type,enum state_type state,
+ char *name,int name_type,int nb_flags, time_t ttl,
+ BOOL bcast,BOOL recurse,
+ struct in_addr send_ip, struct in_addr reply_to_ip);
+struct response_record *queue_netbios_packet(struct subnet_record *d,
+ int fd,int quest_type,enum state_type state,char *name,
+ int name_type,int nb_flags, time_t ttl,
+ BOOL bcast,BOOL recurse,
+ struct in_addr send_ip, struct in_addr reply_to_ip);
+
+/*The following definitions come from nameserv.c */
+
+void remove_name_entry(struct subnet_record *d, char *name,int type);
+void add_my_name_entry(struct subnet_record *d,char *name,int type,int nb_flags);
void add_my_names(void);
void remove_my_names();
void refresh_my_names(time_t t);
-void expire_names(time_t t);
-void response_name_release(struct packet_struct *p);
+void query_refresh_names(void);
+
+/*The following definitions come from nameservreply.c */
+
+void add_name_respond(struct subnet_record *d, int fd, struct in_addr from_ip,
+ uint16 response_id,
+ struct nmb_name *name,
+ int nb_flags, int ttl, struct in_addr register_ip,
+ BOOL new_owner, struct in_addr reply_to_ip);
+void send_name_response(int fd, struct in_addr from_ip,
+ int name_trn_id, int opcode, BOOL success, BOOL recurse,
+ struct nmb_name *reply_name, int nb_flags, int ttl,
+ struct in_addr ip);
void reply_name_release(struct packet_struct *p);
-void response_name_reg(struct packet_struct *p);
void reply_name_reg(struct packet_struct *p);
void reply_name_status(struct packet_struct *p);
void reply_name_query(struct packet_struct *p);
-void process_nmb(struct packet_struct *p);
+
+/*The following definitions come from nameservresp.c */
+
+void debug_state_type(int state);
+void response_netbios_packet(struct packet_struct *p);
+
+/*The following definitions come from namework.c */
+
void reset_server(char *name, int state, struct in_addr ip);
void tell_become_backup(void);
-void do_browser_lists(void);
-void sync_server(enum cmd_type cmd, char *serv_name, char *work_name,
- int name_type,
- struct in_addr ip);
-void update_from_reg(char *name, int type, struct in_addr ip);
-void add_my_domains(char *group);
BOOL same_context(struct dgram_packet *dgram);
BOOL listening_name(struct work_record *work, struct nmb_name *n);
-void process_logon_packet(struct packet_struct *p,char *buf,int len);
BOOL listening_type(struct packet_struct *p, int command);
void process_browse_packet(struct packet_struct *p,char *buf,int len);
-void process_dgram(struct packet_struct *p);
+
+/*The following definitions come from nmbd.c */
+
BOOL reload_services(BOOL test);
+
+/*The following definitions come from nmblib.c */
+
void debug_nmb_packet(struct packet_struct *p);
char *namestr(struct nmb_name *n);
void free_nmb_packet(struct nmb_packet *nmb);
@@ -336,11 +494,23 @@
void make_nmb_name(struct nmb_name *n,char *name,int type,char *this_scope);
BOOL send_packet(struct packet_struct *p);
struct packet_struct *receive_packet(int fd,enum packet_type type,int t);
+
+/*The following definitions come from nmblookup.c */
+
int main(int argc,char *argv[]);
+
+/*The following definitions come from nmbsync.c */
+
char *getsmbpass(char *pass);
-void sync_browse_lists(struct work_record *work, char *name, int nm_type,
- struct in_addr ip);
+void sync_browse_lists(struct subnet_record *d, struct work_record *work,
+ char *name, int nm_type, struct in_addr ip);
+
+/*The following definitions come from params.c */
+
BOOL pm_process(char *pszFileName,BOOL (*sfunc)(char *),BOOL (*pfunc)(char *,char *));
+
+/*The following definitions come from password.c */
+
void generate_next_challenge(char *challenge);
BOOL set_challenge(char *challenge);
BOOL last_challenge(char *challenge);
@@ -360,21 +530,36 @@
BOOL check_hosts_equiv(char *user);
BOOL server_cryptkey(char *buf);
BOOL server_validate(char *buf);
+
+/*The following definitions come from pcap.c */
+
BOOL pcap_printername_ok(char *pszPrintername, char *pszPrintcapname);
void pcap_printer_fn(void (*fn)());
+
+/*The following definitions come from predict.c */
+
int read_predict(int fd,int offset,char *buf,char **ptr,int num);
void do_read_prediction();
void invalidate_read_prediction(int fd);
+
+/*The following definitions come from printing.c */
+
void lpq_reset(int snum);
void print_file(int fnum);
int get_printqueue(int snum,int cnum,print_queue_struct **queue,
print_status_struct *status);
void del_printqueue(int cnum,int snum,int jobid);
void status_printjob(int cnum,int snum,int jobid,int status);
+
+/*The following definitions come from quotas.c */
+
BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize);
BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize);
BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize);
BOOL disk_quotas(char *path, int *bsize, int *dfree, int *dsize);
+
+/*The following definitions come from replace.c */
+
char *Strstr(char *s, char *p);
time_t Mktime(struct tm *t);
int InNetGr(char *group,char *host,char *user,char *dom);
@@ -382,6 +567,9 @@
void *realloc_wrapped(void *ptr,int size,char *file,int line);
void free_wrapped(void *ptr,char *file,int line);
void *memcpy_wrapped(void *d,void *s,int l,char *fname,int line);
+
+/*The following definitions come from reply.c */
+
int reply_special(char *inbuf,char *outbuf);
int reply_tcon(char *inbuf,char *outbuf);
int reply_tcon_and_X(char *inbuf,char *outbuf,int length,int bufsize);
@@ -432,6 +620,9 @@
int reply_writebs(char *inbuf,char *outbuf);
int reply_setattrE(char *inbuf,char *outbuf);
int reply_getattrE(char *inbuf,char *outbuf);
+
+/*The following definitions come from server.c */
+
mode_t unix_mode(int cnum,int dosmode);
int dos_mode(int cnum,char *path,struct stat *sbuf);
int dos_chmod(int cnum,char *fname,int dosmode,struct stat *st);
@@ -473,6 +664,9 @@
char *smb_fn_name(int type);
int chain_reply(int type,char *inbuf,char *inbuf2,char *outbuf,char *outbuf2,int size,int bufsize);
int construct_reply(char *inbuf,char *outbuf,int size,int bufsize);
+
+/*The following definitions come from smbencrypt.c */
+
void str_to_key(uchar *str,uchar *key);
void D1(uchar *k, uchar *d, uchar *out);
void E1(uchar *k, uchar *d, uchar *out);
@@ -481,10 +675,26 @@
void SMBencrypt(uchar *passwd, uchar *c8, uchar *p24);
void E_md4hash(uchar *passwd, uchar *p16);
void SMBNTencrypt(uchar *passwd, uchar *c8, uchar *p24);
+
+/*The following definitions come from smbpass.c */
+
+struct smb_passwd *get_smbpwnam(char *name);
+
+/*The following definitions come from smbpasswd.c */
+
+
+/*The following definitions come from smbrun.c */
+
+
+/*The following definitions come from status.c */
+
void Ucrit_addUsername(pstring username);
unsigned int Ucrit_checkUsername(pstring username);
void Ucrit_addPid(int pid);
unsigned int Ucrit_checkPid(int pid);
+
+/*The following definitions come from system.c */
+
int sys_select(fd_set *fds,struct timeval *tval);
int sys_select(fd_set *fds,struct timeval *tval);
int sys_unlink(char *fname);
@@ -499,7 +709,16 @@
int sys_rename(char *from, char *to);
int sys_chown(char *fname,int uid,int gid);
int sys_chroot(char *dname);
+
+/*The following definitions come from testparm.c */
+
+
+/*The following definitions come from testprns.c */
+
int main(int argc, char *argv[]);
+
+/*The following definitions come from time.c */
+
void GetTimeOfDay(struct timeval *tval);
void TimeInit(void);
int TimeDiff(time_t t);
@@ -514,20 +733,35 @@
time_t make_unix_date3(void *date_ptr);
BOOL set_filetime(char *fname,time_t mtime);
char *timestring(void );
+
+/*The following definitions come from trans2.c */
+
int reply_findclose(char *inbuf,char *outbuf,int length,int bufsize);
int reply_findnclose(char *inbuf,char *outbuf,int length,int bufsize);
int reply_transs2(char *inbuf,char *outbuf,int length,int bufsize);
int reply_trans2(char *inbuf,char *outbuf,int length,int bufsize);
+
+/*The following definitions come from ufc.c */
+
char *ufc_crypt(char *key,char *salt);
+
+/*The following definitions come from uid.c */
+
void init_uid(void);
BOOL become_guest(void);
BOOL become_user(int cnum, int uid);
BOOL unbecome_user(void );
int smbrun(char *cmd,char *outfile);
+
+/*The following definitions come from username.c */
+
char *get_home_dir(char *user);
void map_username(char *user);
struct passwd *Get_Pwnam(char *user,BOOL allow_change);
BOOL user_in_list(char *user,char *list);
+
+/*The following definitions come from util.c */
+
void setup_logging(char *pname,BOOL interactive);
void reopen_logs(void);
BOOL is_a_socket(int fd);
@@ -634,6 +868,9 @@
void BlockSignals(BOOL block);
void ajt_panic(void);
char *readdirname(void *p);
+
+/*The following definitions come from vt_mode.c */
+
int VT_Check(char *buffer);
int VT_Start_utmp(void);
int VT_Stop_utmp(void);
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/reply.c samba-1.9.16alpha11/source/reply.c
--- samba-1.9.16alpha10/source/reply.c Mon Jun 10 15:19:00 1996
+++ samba-1.9.16alpha11/source/reply.c Mon Jul 15 17:55:06 1996
@@ -2062,6 +2062,11 @@
cnum = SVAL(inbuf,smb_tid);
uid = SVAL(inbuf,smb_uid);
+ if (!OPEN_CNUM(cnum)) {
+ DEBUG(4,("Invalid cnum in tdis (%d)\n",cnum));
+ return(ERROR(ERRSRV,ERRinvnid));
+ }
+
Connections[cnum].used = False;
close_cnum(cnum,uid);
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/smb.h samba-1.9.16alpha11/source/smb.h
--- samba-1.9.16alpha10/source/smb.h Mon Jun 10 15:19:02 1996
+++ samba-1.9.16alpha11/source/smb.h Thu Jul 18 20:53:16 1996
@@ -108,10 +108,16 @@
#else
EXTERN int syslog_level;
-#define DEBUG(level,body) ((DEBUGLEVEL>=(level))? \
- (syslog_level = (level), Debug1 body):0)
+#define DEBUG(level,body) ((DEBUGLEVEL>=(level))? (syslog_level = (level), Debug1 body):0)
#endif
+/* this defines the error codes that receive_smb can put in smberrcode */
+#define SMBERR_OK 0
+#define SMBERR_TIMEOUT 1
+#define SMBERR_EOF 2
+#define SMBERR_ERROR 3
+
+
#define DIR_STRUCT_SIZE 43
/* these define all the command types recognised by the server - there
@@ -380,6 +386,15 @@
BOOL server_added; /* used ONLY in ipc.c NOT namework.c */
};
+
+/* used for network interfaces */
+struct interface
+{
+ struct interface *next;
+ struct in_addr ip;
+ struct in_addr bcast;
+ struct in_addr nmask;
+};
/* this is used for smbstatus */
struct connect_record
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/smbpass.c samba-1.9.16alpha11/source/smbpass.c
--- samba-1.9.16alpha10/source/smbpass.c Mon Jun 10 15:19:02 1996
+++ samba-1.9.16alpha11/source/smbpass.c Thu Jul 18 20:53:16 1996
@@ -109,8 +109,7 @@
/*
* Routine to search the smbpasswd file for an entry matching the username.
*/
-struct smb_passwd *
-get_smbpwnam(char *name)
+struct smb_passwd *get_smbpwnam(char *name)
{
/* Static buffers we will return. */
static struct smb_passwd pw_buf;
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/smbtar samba-1.9.16alpha11/source/smbtar
--- samba-1.9.16alpha10/source/smbtar Sat May 4 17:50:25 1996
+++ samba-1.9.16alpha11/source/smbtar Sun Jun 30 15:17:26 1996
@@ -138,4 +138,3 @@
-E -N $log -D "'$cdcmd'" \
-T${tarcmd}${tarargs} $blocksize $newer $tapefile $* $verbose
-
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/system.c samba-1.9.16alpha11/source/system.c
--- samba-1.9.16alpha10/source/system.c Sun May 5 17:18:39 1996
+++ samba-1.9.16alpha11/source/system.c Sun Jun 30 15:17:26 1996
@@ -25,13 +25,17 @@
/*
The idea is that this file will eventually have wrappers around all
- important system calls in samba. The aim is twofold:
+ important system calls in samba. The aims are:
- to enable easier porting by putting OS dependent stuff in here
- to allow for hooks into other "pseudo-filesystems"
- to allow easier integration of things like the japanese extensions
+
+ - to support the philosophy of Samba to expose the features of
+ the OS within the SMB model. In general whatever file/printer/variable
+ expansions/etc make sense to the OS should be acceptable to Samba.
*/
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/uninstallbin.sh samba-1.9.16alpha11/source/uninstallbin.sh
--- samba-1.9.16alpha10/source/uninstallbin.sh Thu Jan 1 10:00:00 1970
+++ samba-1.9.16alpha11/source/uninstallbin.sh Fri Jul 5 13:53:11 1996
@@ -0,0 +1,43 @@
+#!/bin/sh
+#4 July 96 Dan.Shearer@UniSA.edu.au
+
+INSTALLPERMS=$1
+BASEDIR=$2
+BINDIR=$3
+LIBDIR=$4
+VARDIR=$5
+shift
+shift
+shift
+shift
+shift
+
+if [ ! -d $BINDIR ]; then
+ echo Directory $BINDIR does not exist!
+ echo Do a "make installbin" or "make install" first.
+ exit 1
+fi
+
+for p in $*; do
+ if [ ! -f $BINDIR/$p ]; then
+ echo $BINDIR/$p does not exist!
+ else
+ echo Removing $BINDIR/$p
+ rm -f $BINDIR/$p
+ if [ -f $BINDIR/$p ]; then
+ echo Cannot remove $BINDIR/$p... does $USER have privileges?
+ fi
+ fi
+done
+
+
+cat << EOF
+======================================================================
+The binaries have been uninstalled. You may restore the binaries using
+the command "make installbin" or "make install" to install binaries,
+man pages and shell scripts. You can restore a previous version of the
+binaries (if there were any) using "make revert".
+======================================================================
+EOF
+
+exit 0
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/uninstallman.sh samba-1.9.16alpha11/source/uninstallman.sh
--- samba-1.9.16alpha10/source/uninstallman.sh Thu Jan 1 10:00:00 1970
+++ samba-1.9.16alpha11/source/uninstallman.sh Fri Jul 5 13:53:11 1996
@@ -0,0 +1,31 @@
+#!/bin/sh
+#4 July 96 Dan.Shearer@UniSA.edu.au
+
+MANDIR=$1
+SRCDIR=$2
+
+echo Uninstalling man pages from $MANDIR
+
+for sect in 1 5 7 8 ; do
+ for m in $MANDIR/man$sect ; do
+ for s in $SRCDIR../docs/*$sect; do
+ FNAME=$m/`basename $s`
+ if test -f $FNAME; then
+ echo Deleting $FNAME
+ rm -f $FNAME
+ test -f $FNAME && echo Cannot remove $FNAME... does $USER have privileges?
+ else
+ echo $FNAME does not exist! Check defines in the Makefile
+ fi
+ done
+ done
+done
+
+cat << EOF
+======================================================================
+The man pages have been uninstalled. You may install them again using
+the command "make installman" or make "install" to install binaries,
+man pages and shell scripts.
+======================================================================
+EOF
+exit 0
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/uninstallscripts.sh samba-1.9.16alpha11/source/uninstallscripts.sh
--- samba-1.9.16alpha10/source/uninstallscripts.sh Thu Jan 1 10:00:00 1970
+++ samba-1.9.16alpha11/source/uninstallscripts.sh Fri Jul 5 13:53:12 1996
@@ -0,0 +1,37 @@
+#!/bin/sh
+# 5 July 96 Dan.Shearer@UniSA.Edu.Au - almost identical to uninstallbin.sh
+
+INSTALLPERMS=$1
+BINDIR=$2
+
+shift
+shift
+
+if [ ! -d $BINDIR ]; then
+ echo Directory $BINDIR does not exist!
+ echo Do a "make installscripts" or "make install" first.
+ exit 1
+fi
+
+for p in $*; do
+ if [ ! -f $BINDIR/$p ]; then
+ echo $BINDIR/$p does not exist!
+ else
+ echo Removing $BINDIR/$p
+ rm -f $BINDIR/$p
+ if [ -f $BINDIR/$p ]; then
+ echo Cannot remove $BINDIR/$p... does $USER have privileges?
+ fi
+ fi
+done
+
+cat << EOF
+======================================================================
+The scripts have been uninstalled. You may reinstall them using
+the command "make installscripts" or "make install" to install binaries,
+man pages and shell scripts. You may recover a previous version (if any
+with "make revert".
+======================================================================
+EOF
+
+exit 0
diff -u -r --new-file --exclude=CVS samba-1.9.16alpha10/source/version.h samba-1.9.16alpha11/source/version.h
--- samba-1.9.16alpha10/source/version.h Mon Jun 10 15:19:48 1996
+++ samba-1.9.16alpha11/source/version.h Thu Jul 18 20:53:51 1996
@@ -1 +1 @@
-#define VERSION "1.9.16alpha10"
+#define VERSION "1.9.16alpha11"